• Overview of Data
    • Comparison of Two Categorical Variables
    • Comparison of Two Numerical Variables
    • Comparison of a Numerical and Categorical Variables
  • Conclusion for Comparison of Variables
  • Overview of Missing Variables
    • Mode Imputation for Categorical Variables
    • Regression-Based Imputation for Numerical Variables
    • MICE Imputation
  • Skewness
  • Transforming Data
  • Analyzing Data
    • Random Forest
    • Stepwise Logistic Regression
  • Cross-Validation
  • ROC Curve and AOC Curve
    • Confusion Matrices
    • ROC Curve
    • AUC (Area under the Curve)
    • AUC Value
  • Conclusion for Model Fit

Overview of Data

The purpose of this dataset was to help find predictors of diabetes. The goal is to help medical professionals identify patients with potential risk factors of diabetes.The dataset contains information on patient demographics such as age and gender, as well as medical information including blood glucose levels and hypertension. The observations in this dataset were obtained from research studies and healthcare institutions. The dataset was obtained via Kaggle.

Mustafa, T. Z. (2021). Diabetes Prediction Dataset. Kaggle. https://www.kaggle.com/datasets/iammustafatz/diabetes-prediction-dataset

The dataset consists of 8 predictor variables for diabetes:

  • gender - the patient’s gender as male or female.

  • age - the age of the patient in years.

  • hypertension - yes or no, on whether the patient has hypertension.

  • heart disease - yes or no, on whether the patient has heart disease.

  • smoking history - the patient’s smoking history indicated as never, no info, current, former or not current.

  • bmi - the patient’s body mass index (kg/m**2).

  • HbA1c level - the patient’s average blood sugar level over the past 2-3 months (%).

  • blood glucose level - amount of blood sugar in the patient’s blood (mg/dL).

#load in dataset
data <-read.csv('https://raw.githubusercontent.com/GabbyK8/Datasets/refs/heads/main/diabetes_prediction_dataset.csv')
diabetesd<-data

#change heart disease, diabetes and hypertension to 1 and 0 for easier use in MICE.
data$diabetes <- recode(data$diabetes, "1"="Yes", "0"="No")
data$hypertension <- recode(data$hypertension, "1"="Yes", "0"="No")
data$heart_disease <- recode(data$heart_disease, "1"="Yes", "0"="No")

#plot interaction between diabetes and hypertension.
ggplot(data, aes(x = hypertension, fill = diabetes)) +
  geom_bar(position = "dodge") + # Use "stack" for a stacked bar chart
  labs (title="Risk of Diabetes by Hypertension", x="Hypertension", y= "Frequency",
        fill= "Diabetes")
The plot of shows the frequency of patients with diabetes and hypertension. The plot indiactes a higher frequency of patients not having diabetes and not having hypertension. There does not seem to be an interaction between having diabetes and having hypertension based on the low frequency of patients having both.

The plot of shows the frequency of patients with diabetes and hypertension. The plot indiactes a higher frequency of patients not having diabetes and not having hypertension. There does not seem to be an interaction between having diabetes and having hypertension based on the low frequency of patients having both.

Comparison of Two Categorical Variables

The purpose of this graph is to show the relationship between having hypertension and diabetes. For this graph, I changed the values of 1 in both the diabetes and hypertension variable to “Yes” and the value 0 to “No.” These integers were meant to represent categorical variables with 1 correlating to being positive for hypertension or diabetes and 0 correlating to being negative to hypertension or diabetes. Based on our graph, we can see that there is no correlation between having diabetes and having hypertension, with most patients within our sample having neither diabetes or hypertension. Thus, hypertension would not be a good predictor of diabetes within patients.

interact = ggplot(data, aes(x =blood_glucose_level , y = HbA1c_level, group = diabetes, color = diabetes)) +
  geom_line(size = 1) +  # Lines representing interaction
  geom_point(size = 2) + # Points for data
  labs(
    title = "Interaction of Blood Glucose and HbA1c Levels",
    x = "Blood Glucose Level",
    y = "HbA1c Level",
    color = "Presence of Diabetes"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
    axis.text = element_text(size = 12),
    legend.position = "top"
  )
interact
The plot shows the interaction between blood glucose levels and HbA1c levels on diabetes. Based on the plot, higher blood glucose levels and HbA1c levels are positively correlated with the presence of diabetes. In comparison, lower levels, indicate that a patient will more commonly not have diabetes. The height of the points shown for diabetes represent the levels of HbA1c, based on the plot, HbA1c levels predict the presence of diabetes more often than blood glucose levels.

The plot shows the interaction between blood glucose levels and HbA1c levels on diabetes. Based on the plot, higher blood glucose levels and HbA1c levels are positively correlated with the presence of diabetes. In comparison, lower levels, indicate that a patient will more commonly not have diabetes. The height of the points shown for diabetes represent the levels of HbA1c, based on the plot, HbA1c levels predict the presence of diabetes more often than blood glucose levels.

Comparison of Two Numerical Variables

The two variables being compared here are Blood Glucose Level and HbA1c Level. HbA1cc is a shortened term for hemoglobin A1c. Hb1Ac level is a measure of average blood sugar levels over 2-3 months and is measured in %. Blood glucose level is the amount of blood sugar in a patients blood at a given time. Our plot shows a correlation between high levels in HbA1c and blood glucose levels and it’s relationship with diabetes. This plot suggests patients with high levels of HbA1c and blood glucose levels are at high risk for diabetes.

#plot of a numerical and categorical variable
 boxplot(data$age ~ data$diabetes,
         xlab="Presence of Diabetes",
         ylab="Patient Age",
         col = c("skyblue", "purple"),
         main="Visualization of Diabetes by Age",
         cex.main = 1.1,
         col.main = "navy")
The boxplot shows the relationship between age and presence of diabetes. The boxplot shows that older patients on average are more often have diabetes. There are a few outliers in the diabetes population that appear to be under the age of 20 years. This could be representative of patients with Type I diabetes, since the data does not distinguish between Type I and Type II diabetes.

The boxplot shows the relationship between age and presence of diabetes. The boxplot shows that older patients on average are more often have diabetes. There are a few outliers in the diabetes population that appear to be under the age of 20 years. This could be representative of patients with Type I diabetes, since the data does not distinguish between Type I and Type II diabetes.

Comparison of a Numerical and Categorical Variables

This chart shows the relationship between age and diabetes diagnosis. This chart shows that as patients grow older they are at higher risk for diabetes. This would make age a predictor for diabetes, with the average age for those without diabetes being 40 years and 60 years for those with diabetes. However, we can see that we do have a few outliers for those with diabetes with some patients being diagnosed at 20 or younger. This could be from the population of people with Type I diabetes which is usually diagnosed in patients under 20. Our dataset does not distinguish between type I and type II diabetes.

Conclusion for Comparison of Variables

Diabetes can be predicted using age, blood glucose levels, and HbA1c levels in patients. However, our results showed hypertension is not a good predictor of diabetes. Based on our findings, it would be interesting to look at factors that occur once a patient becomes older that could lead to diabetes at an older age. As well, diet could be another factor to look into, such as grams of sugar consumed on a daily or weekly basis, to see if sugar consumption can predict diabetes. Another important thing to analyze in future studies would be Type I versus Type II diabetes, as it could be the reason for some of the outliers in the boxplot.

Overview of Missing Variables

An important step in data analysis for machine learning is handling missing values. Missing values in a dataset can occur for many reasons, but not limited to non-response in surveys, participants leaving the study, data entry errors and system limitations. If missing values are not addressed, models can become biased and accuracy of the anaylysis can decrease. This section examines different imputation strategies to effectively handle missing values.

The imputation methods we will examine include:

Replacement Imputation for Categorical Features: Mode imputation.

Regression-based Imputation for Numerical Features: Predictive modeling to estimate missing values.

Multiple Imputation: Advanced methods such as MICE to improve robustness.

# create random observation ID and replace the corresponding obs with missing
ltr.missing.id <- sample(1:1000, 50, replace = FALSE)
gpa.missing.id <- sample(1:1000, 15, replace = FALSE) 
diabetesd$bmi[ltr.missing.id] <- NA
diabetesd$heart_disease[gpa.missing.id] <- NA
diabetesd$smoking_history[diabetesd$smoking_history == "No Info"] <- NA

Mode Imputation for Categorical Variables

In this method, missing variables are replaced with the most frequent category of the corresponding variable. Mode imputation ensures consistency and works well when missing values are randomly distributed. Below, mode imputation is used on the variable, heart disease, which is 1 if the patient has heart disease and 0 if the patient does not have heart disease.The variable smoking history had current, former, no info, never, and ever as possible values. No Info indicates that we do not have information on the participant’s smoking history and will be treated as a missing values.

    original        original2         imputed_modehd    imputed_modesh    
 Min.   :0.00000   Length:100000      Min.   :0.00000   Length:100000     
 1st Qu.:0.00000   Class :character   1st Qu.:0.00000   Class :character  
 Median :0.00000   Mode  :character   Median :0.00000   Mode  :character  
 Mean   :0.03943                      Mean   :0.03942                     
 3rd Qu.:0.00000                      3rd Qu.:0.00000                     
 Max.   :1.00000                      Max.   :1.00000                     
 NA's   :15                                                               
The plot shows the comparison between the original data containing missing values for the variables heart disease and smoking history, and the data after using mode impute. The histograms show that mode impute used what was most common to replace the missing values. This is seen clearly in the variable smoking history, where the category never went from originally a count of about 40,000 to about 70,000. Heart disease had a small amount of missing data (only 15), however the 15 missing were changed to 0, indicating the patient would not have heart disease.

The plot shows the comparison between the original data containing missing values for the variables heart disease and smoking history, and the data after using mode impute. The histograms show that mode impute used what was most common to replace the missing values. This is seen clearly in the variable smoking history, where the category never went from originally a count of about 40,000 to about 70,000. Heart disease had a small amount of missing data (only 15), however the 15 missing were changed to 0, indicating the patient would not have heart disease.

Regression-Based Imputation for Numerical Variables

Using regression models, we can estimate missing values. For the variable, bmi, we can predict the missing values using estimates from our model. Bmi is a continuous variable, unlike the previous example where our values could only be 0 or 1. In this method, a linear model was created to help create estimates of our values.

#create a dataset for regression impute
regimpute<-diabetesd

# Identify rows where BMI is missing
missing_rows <- which(is.na(diabetesd$bmi))  # Get row indices


# Train a linear model using complete cases
lm_model <- lm(bmi ~ age + blood_glucose_level + HbA1c_level + heart_disease + hypertension + diabetes, 
               data = regimpute, na.action = na.exclude)

# Impute missing BMI values using the model
diabetesd$bmi[missing_rows] <- predict(lm_model, newdata = regimpute[missing_rows, ])


dep.mi <- bind_rows(
  data.frame(value = diabetesd$bmi, imputed = regimpute$bmi))
             #imp = "dep.imp1")


i7<-boxplot(diabetesd$bmi,
main = "Mean bmi in Original Data",
xlab = "BMI",
col = "blue",
border = "black",
horizontal = TRUE,
notch = TRUE
)
The boxplots show the comparison of the variable bmi before and after regression imputation.

The boxplots show the comparison of the variable bmi before and after regression imputation.

i8 <-boxplot(regimpute$bmi,
main = "Regression Imputation for BMI",
xlab = "BMI",
col = "red",
border = "black",
horizontal = TRUE,
notch = TRUE
)
The boxplots show the comparison of the variable bmi before and after regression imputation.

The boxplots show the comparison of the variable bmi before and after regression imputation.

MICE Imputation

MICE is multiple imputation techniques used to impute missing values. This method also uses regression models and accounts for uncertainty by generating multiple possible values. Using MICE, the variables smoking history, heart disease, and bmi, can be imputated within one function. MICE can handle different types of variables, imputates based on the relationship between variables and it accounts for variability in missing data.
Based on the three graphs, MICE seems to have produced values that appear almost identical to the original dataset. Mode impute seems to be slightly different since it relies on filling missing values with the most common value. In this case, mode impute filled all missing values as 0 and under-represented 1.

Based on the three graphs, MICE seems to have produced values that appear almost identical to the original dataset. Mode impute seems to be slightly different since it relies on filling missing values with the most common value. In this case, mode impute filled all missing values as 0 and under-represented 1.

#plot comparisons for smoking history
g4 <- ggplot(df_imputed, aes(x = smoking_history)) +
  geom_bar( fill = "purple", color = "#000000", position = "identity") +
  ggtitle("MICE") +
  labs(x="Smoking History")+
  theme_classic()
g5 <- ggplot(value_imputed, aes(x = original2)) +
  geom_bar( fill = "red", color = "#000000", position = "identity") +
  ggtitle("Original Smoking History") +
  labs(x="Smoking History")+
  theme_classic()
g6 <- ggplot(value_imputed, aes(x = imputed_modesh)) +
  geom_bar( fill = "blue", color = "#000000", position = "identity") +
  ggtitle("Mode-imputed") +
  labs(x="Smoking History")+
  theme_classic()
plot_grid(g4,g5,g6, nrow=3, ncol=1)
The bar graphs show the comparison of the original data to mode imputation and MICE. MICE appears to have dispersed the data more evenly across the different categories, while mode imputation has only added values to the category never.

The bar graphs show the comparison of the original data to mode imputation and MICE. MICE appears to have dispersed the data more evenly across the different categories, while mode imputation has only added values to the category never.

#plot comparisons for bmi
g7<-boxplot(diabetesd$bmi,
main = "Mean BMI in Original Data",
xlab = "BMI",
col = "blue",
border = "black",
horizontal = TRUE,
notch = TRUE
)
The boxplots show the comparison of the original data to both MICE and regression imputation. The appear to have similar results, based on mean which is indicated by the black line within each box.

The boxplots show the comparison of the original data to both MICE and regression imputation. The appear to have similar results, based on mean which is indicated by the black line within each box.

g8 <-boxplot(regimpute$bmi,
main = "Regression Imputation for BMI",
xlab = "BMI",
col = "red",
border = "black",
horizontal = TRUE,
notch = TRUE
)
The boxplots show the comparison of the original data to both MICE and regression imputation. The appear to have similar results, based on mean which is indicated by the black line within each box.

The boxplots show the comparison of the original data to both MICE and regression imputation. The appear to have similar results, based on mean which is indicated by the black line within each box.

g9 <-boxplot(df_imputed$bmi,
main = "MICE for BMI",
xlab = "BMI",
col = "purple",
border = "black",
horizontal = TRUE,
notch = TRUE
)
The boxplots show the comparison of the original data to both MICE and regression imputation. The appear to have similar results, based on mean which is indicated by the black line within each box.

The boxplots show the comparison of the original data to both MICE and regression imputation. The appear to have similar results, based on mean which is indicated by the black line within each box.

model5 <- with(df_mice, lm(diabetes ~ bmi+ heart_disease+ smoking_history ))
summary(pool(model5)) 
                        term      estimate    std.error  statistic         df
1                (Intercept) -1.589271e-01 0.0042324895 -37.549331  7809.1387
2                        bmi  8.389138e-03 0.0001290303  65.016790 98218.7361
3             heart_disease1  2.215433e-01 0.0044014918  50.333683 97912.1342
4        smoking_historyever  4.340230e-03 0.0044699572   0.970978   758.3466
5      smoking_historyformer  3.921079e-02 0.0034267231  11.442648  1492.5796
6       smoking_historynever -4.314363e-05 0.0026854000  -0.016066   835.6005
7 smoking_historynot current  6.005163e-03 0.0038588408   1.556209   545.3864
        p.value
1 7.985880e-284
2  0.000000e+00
3  0.000000e+00
4  3.318688e-01
5  4.026967e-29
6  9.871856e-01
7  1.202385e-01

The statistics above show the summary of the newly imputed missing variables through MICE. Based on our p-values, smoking history will most likely not be chosen for the final model as it’s significance level is greater than 0.05, indicating an insignificant predictor variable.

Skewness

Skewness is a measure of symmetry within a distribution. The skewness measurements below are of the variables age, bmi, HbA1c level, and blood glucose level, respectively. When skewness is equal to 0, we can assume the data is normally distributed. When skewness is greater than 0, our data is positively skewed, while a value less than zero indicates negatively skewed data. For the diabetes dataset, the variables bmi and blood glucose level are 1 or about 1, which indicate a significant right skew in the distribution.

age1<- skewness(df_imputed$age) 
bmi1<-skewness(df_imputed$bmi) 
HbA1c1<-skewness( df_imputed$HbA1c_level) 
glucose1<-skewness(df_imputed$blood_glucose_level)

mytable<-data.frame(age1,bmi1,HbA1c1, glucose1)
pander(mytable, caption= "Skewness of Numeric Variables",position="center")
Skewness of Numeric Variables
age1 bmi1 HbA1c1 glucose1
-0.05198 1.043 -0.06685 0.8216

Transforming Data

To handle our skewed variables, we can normalize the variables bmi and blood glucose level. Normalization rescales data into a fixed range of [0,1]. By normalizing our data, we can fix skewness and create normally distributed data. The variables, age and HbA1c level have been standardized to keep the distribution centered. Standardization is used to create a mean of 0 and a standard deviation of 1, to follow a normal distribution. Based on the results below, we can see that the transformation has corrected the right skew in the data from before.

df_trans <- df_imputed  # Copy original dataset after MICE

#ensure diabetes is numeric and a factor
df_trans$diabetes<- as.numeric(as.factor(df_trans$diabetes))
# Min-Max Normalization
normalize <- function(x) {
  if (max(x) - min(x) == 0) return(rep(0, length(x)))  # Prevent division by zero
  return((x - min(x)) / (max(x) - min(x)))
}

#apply normalization
df_trans$bmi <- normalize(df_imputed$bmi)
df_trans$blood_glucose_level <- normalize(df_imputed$blood_glucose_level)

# Z-Score Standardization
standardize <- function(x) {
  return((x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE))
}

#apply standardization
df_trans$age <- standardize(df_trans$age)
df_trans$HbA1c_level <- standardize(df_trans$HbA1c_level)

# Apply Log Transformation to Fix Skewness (if necessary)
df_trans$bmi <- log1p(df_trans$bmi)  # log(1 + x) avoids log(0) issues
df_trans$blood_glucose_level <- log1p(df_trans$blood_glucose_level)

bmi2 <- skewness(df_trans$bmi)
age2 <- skewness(df_trans$age)
HbA1c2<- skewness(df_trans$HbA1c_level)
glucose2<- skewness(df_trans$blood_glucose_level)

newtable<-data.frame(bmi2,age2,HbA1c2,glucose2)
pander(newtable, caption="Newly Transformed Data", position="center")
Newly Transformed Data
bmi2 age2 HbA1c2 glucose2
0.674 -0.05198 -0.06685 0.2867

Transforming our data has successfully decreased skewness in our variables. We can see bmi and blood glucose level are no longer about 1.

# Combine old and new data for comparison
df_compare <- data.frame(
  bmi_original = df_imputed$bmi,
  bmi_transformed = df_trans$bmi,
  blood_glucose_original = df_imputed$blood_glucose_level,
  blood_glucose_transformed = df_trans$blood_glucose_level
)

# Reshape data for ggplot
df_long <- melt(df_compare)

# Plot histograms
ggplot(df_long, aes(x = value, fill = variable)) +
  geom_histogram(alpha = 0.6, bins = 30, position = "identity") +
  facet_wrap(~ variable, scales = "free") +
  theme_minimal() +
  labs(title = "Comparison of Original vs. Transformed Data", x = "Value", y = "Count")
We can see in the graphs above that after transforming the dataset, the data seems to follow a normal distribution more closely.This is apparent in the histograms appearing more in a bell shape curve.

We can see in the graphs above that after transforming the dataset, the data seems to follow a normal distribution more closely.This is apparent in the histograms appearing more in a bell shape curve.

Analyzing Data

The next step is to find which variables are significantly important when trying to predict diabetes. By using feature selection, we are able to predict possible best fit models for our variable, diabetes. For this data, we will focus on logistic regression. The variables of interest, diabetes, is a binary variable indicating linear regression would not make an ideal model.

Random Forest

First, we will look at the best model selected by feature selection through random forest:

# Prepare the data
df_trans$diabetes <- as.factor(df_trans$diabetes)


# Set up RFE control with random forest
control <- rfeControl(functions = rfFuncs, method = "cv", number = 10)

# Apply RFE to identify top features
results <- rfe(
  x = df_trans[, !colnames(df_trans) %in% "diabetes"],
  y = df_trans$diabetes,
  sizes = c(1:9),
  rfeControl = control
)

# Print the selected features
models<-data.frame(predictors(results))
pander(models, caption="Random Forest Selected Model",position="center")
Random Forest Selected Model
predictors.results.
HbA1c_level
blood_glucose_level
bmi
heart_disease
age
hypertension
gender

The table shows the selected variables random forest has selected to use for our model

Stepwise Logistic Regression

Next, let’s look and stepwise logistic regression

#Stepwise Logistic Regression
# Fit a full logistic regression model with all predictors
full_model <- glm(diabetes ~ ., data = df_trans, family = binomial)

# Perform stepwise selection (default is backward elimination)
step_model1 <- step(full_model, direction = "both")
Start:  AIC=23046.9
diabetes ~ gender + age + hypertension + heart_disease + smoking_history + 
    bmi + HbA1c_level + blood_glucose_level

                      Df Deviance   AIC
- smoking_history      4    23028 23044
<none>                      23023 23047
- gender               1    23077 23099
- heart_disease        1    23176 23198
- hypertension         1    23308 23330
- bmi                  1    24361 24383
- age                  1    25095 25117
- blood_glucose_level  1    30572 30594
- HbA1c_level          1    34857 34879

Step:  AIC=23043.94
diabetes ~ gender + age + hypertension + heart_disease + bmi + 
    HbA1c_level + blood_glucose_level

                      Df Deviance   AIC
<none>                      23028 23044
+ smoking_history      4    23023 23047
- gender               1    23086 23100
- heart_disease        1    23184 23198
- hypertension         1    23314 23328
- bmi                  1    24369 24383
- age                  1    25191 25205
- blood_glucose_level  1    30581 30595
- HbA1c_level          1    34865 34879
pander(summary(step_model1))
  Estimate Std. Error z value Pr(>|z|)
(Intercept) -9.99 0.1105 -90.37 0
gender 0.2702 0.03536 7.641 2.15e-14
age 1.034 0.02428 42.58 0
hypertension 0.8032 0.04665 17.22 1.977e-66
heart_disease1 0.7626 0.06015 12.68 7.801e-37
bmi 10.24 0.2809 36.44 1.124e-290
HbA1c_level 2.491 0.03768 66.12 0
blood_glucose_level 10.3 0.149 69.11 0

(Dispersion parameter for binomial family taken to be 1 )

Null deviance: 58163 on 99999 degrees of freedom
Residual deviance: 23028 on 99992 degrees of freedom

The coefficients shown above are the ones stepwise logistic regression has chosen for the final model. They are HbA1c level, blood glucose level, bmi, hypertension, gender, and age.

Both selection types selected the same model! However I will still go through the steps of cross-validation as though I was comparing the two models.

Cross-Validation

Let’s explore cross-validation to see which model is best fit. For logistic regression, it is meaningful to look at accuracy and kappa.

#add classification
df_trans$diabetes<- factor(ifelse(df_trans$diabetes==1, "Yes","No"))

train_control <- trainControl(
  method = "cv",         # cross-validation
  number = 10,           # 10-fold
  classProbs = TRUE # use if you're tracking AUC, Sensitivity, etc.
)

#run CV model
cv_model <- train(
  diabetes ~ hypertension + gender +age + HbA1c_level + blood_glucose_level + heart_disease + bmi, 
  data=df_trans, 
  method = "glm", 
  family = "binomial", 
  trControl = train_control
  )

pander(print(cv_model))

Generalized Linear Model

1e+05 samples 7e+00 predictors 2e+00 classes: ‘No’, ‘Yes’

No pre-processing Resampling: Cross-Validated (10 fold) Summary of sample sizes: 90000, 90000, 90000, 90000, 90000, 90000, … Resampling results:

Accuracy Kappa
0.95934 0.7012814

Accuracy Kappa
0.95934 0.7012814

Accuracy shows the overall correctness of the model predictions and kappa measures the levels of agreement between variables. Values closer to 1 suggest higher accuracy and better agreement. This model suggests high accuracy and high agreement based on the values.

ROC Curve and AOC Curve

Confusion Matrices

ROC is also known as Receiver Operating Characteristic Analysis. It is a technique using graphs that evaluates the performance of a binary model. Before plotting the ROC curve, it is necessary to calculate the true positive rate (TPR) and false positive rate (FPR). Below, are confusion matrices that were used to calculate those values.

#ROC and AUC
df_trans$diabetes <- as.factor(df_trans$diabetes)

# fit a logistic
model.logit <- glm(diabetes ~ age + gender+ bmi+hypertension + heart_disease + blood_glucose_level+ HbA1c_level , family = binomial, data = df_trans)
# predict probability of P(Y = "Yes")
probabilities <- round(as.vector(predict(model.logit, type = "response")),3)
#
thresholds <- c(0.0, 0.25, 0.5, 0.75, 1.0)

# Loop through thresholds and create confusion matrices
for (threshold in thresholds) {
  cat("\nConfusion Matrix for Threshold =", threshold, "\n")
  
  # Convert probabilities to predictions
  # am: 1 = manual transmission, 0 = automatic transmission
  predictions <- ifelse(probabilities > threshold, "Yes", "No")
    all_levels <- union(levels(factor(df_trans$diabetes)), levels(factor(predictions)))
    # Generate confusion matrix
  cm <- confusionMatrix(factor(predictions, levels=all_levels), factor(df_trans$diabetes,levels=all_levels), positive = "Yes")
  print(cm$table)
}

Confusion Matrix for Threshold = 0 
          Reference
Prediction    No   Yes
       No    352     0
       Yes  8148 91500

Confusion Matrix for Threshold = 0.25 
          Reference
Prediction    No   Yes
       No   4217   144
       Yes  4283 91356

Confusion Matrix for Threshold = 0.5 
          Reference
Prediction    No   Yes
       No   5308   868
       Yes  3192 90632

Confusion Matrix for Threshold = 0.75 
          Reference
Prediction    No   Yes
       No   6322  3340
       Yes  2178 88160

Confusion Matrix for Threshold = 1 
          Reference
Prediction    No   Yes
       No   8500 91500
       Yes     0     0

ROC Curve

#create ROC curve

TPR = c(1,91500/(91500+0), 91356/(91356+144), 90632/(90632+868), 88160/(88160+3340), 0/(91500+0))
FPR = c(1,352/(352+8148), 4282/(4282+4218), 3193/(5307+3193), 2178/(2178+6322), 0/(8500+0))
plot(FPR, TPR, type = "b", main = "An Illustrative ROC Curve", col ="blue",
     xlab="1 - Specifity (FPR)", ylab = "Sensitivity (TPR)")
# add a off-diagonal representing random guess algorithm in binary prediction
abline(0,1, lty = 2, col = "red")
# legend
legend("bottomright", c("Logistic Model", "Random Guess"),
       col=c("blue", "red"), lty = 1:2, bty="n", cex = 0.9)

AUC (Area under the Curve)

AUC quantifies the performance of the ROC curve into a single value that ranges from 0 to 1. The plot below uses the Riemann Sum approximation to estimate the area under the curve.

#AUC
TPR = round(c(1,91500/(91500+0), 91356/(91356+144), 90632/(90632+868), 88160/(88160+3340), 0/(91500+0)),3)
FPR = round(c(1,352/(352+8148), 4282/(4282+4218), 3193/(5307+3193), 2178/(2178+6322), 0/(8500+0)),3)
TPR0 = TPR[7:1]
FPR0 = FPR[7:1]
#plot(FPR0, TPR0, type = "b")
datSenSpe = data.frame(TPR0, FPR0)
ggROC = ggplot(data = datSenSpe, aes(x = FPR0, y=TPR0)) +
        geom_line(col = "steelblue") +
        geom_point(col = "red") +
        geom_segment(x = FPR0, y = 0, xend = FPR0, yend = TPR0, color = 4) +
        geom_segment(x = 0, y = 0, xend = FPR0[7], yend = 0, color = 6) +
        ggtitle("Approximating the AUC of Logistic Model") +
        xlab("1-specificity (FPR)") + 
        ylab("Sensitivity (TPR)") +
        annotate("text", x = 0.025, y = 0.125, label= "A") + 
        annotate("text", x = 0.105, y = 0.5, label = "B") +
        annotate("text", x = 0.605, y = 0.5, label = "C") +
        theme(plot.title = element_text(hjust = 0.5),
              legend.position = c(0.8, 0.2),
              plot.margin = unit(c(0.15, 0.15, 0.75, 0.15), "inches"),
              axis.line = element_line(size = 2, colour = "navy", linetype=1))
# partition the region under the ROC into trapezoids
ggplotly(ggROC)
ABC0.000.250.500.751.000.000.250.500.751.00
Approximating the AUC of Logistic Model1-specificity (FPR)Sensitivity (TPR)

AUC Value

The are under the curve is equal to 0.9795 which is close to 1, thus indicating an ideal model.

A<-(0.041*1)/2
B<- ((0.504-0.041)*1)
C<- ((1-0.504)*1)

AUC<- A+B+C
pander(AUC, caption= "Area under the Curve", position="Center")

0.9795

Conclusion for Model Fit

Our best fit model is :

 Diabetes=9.990.27×gender1.03×age0.8×hypertension0.76×heartdisease10.24×bmi2.49×HbA1c level10.3×blood glucose level

The best fit model was selected based on a variety of different features. Both stepwise selection and random forest selected the model as best fit. After running performance analyses on the model, the model was shown to be of high performance. This means that the variables chosen for the final model are significant for predicting diabetes. The model chose not to select smoking history as significant predictor for the response variable. A possible suggestion for this would be to reduce the number of response values to a binary response. Such as, “Have you ever smoked?” and have the response be “Yes” or “No”. This could help in predicting the relationship between smoking and diabetes.

LS0tCnRpdGxlOiAiQXBwbGllZCBNYWNoaW5lIExlYXJuaW5nIGZvciBEYXRhIEFuYWx5c2lzIgphdXRob3I6ICJHYWJyaWVsbGEgS2hhbGlsIgpkYXRlOiAiMjAyNS0wMi0xOCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHdvcmRfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAga2VlcF9tZDogeWVzCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIGZpZ193aWR0aDogMwogICAgZmlnX2hlaWdodDogMwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCgpgYGB7PWh0bWx9Cgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovCgpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLwogIGZvbnQtc2l6ZTogMjJweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwp9Cmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogbmF2eTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgdGhlIGRhdGUgICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LXdlaWdodDogYm9sZDsKfQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAyMnB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwp9CmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDMgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9CgpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQoKPC9zdHlsZT4KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikKICAgbGlicmFyeShrbml0cikKfQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpCmxpYnJhcnkodGlkeXZlcnNlKQp9CmlmICghcmVxdWlyZSgiR0dhbGx5IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikKbGlicmFyeShHR2FsbHkpCn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgKSAgCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFZJTSkgCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoRGVzY1Rvb2xzKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkobWljZSkKbGlicmFyeShtb21lbnRzKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHJlc2hhcGUyKSAgIyBGb3IgZGF0YSByZXNoYXBpbmcKbGlicmFyeShjYXJldCkKbGlicmFyeShwUk9DKQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShmYXN0RHVtbWllcykKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHBhbmRlcikKYGBgCiMgT3ZlcnZpZXcgb2YgRGF0YQoKVGhlIHB1cnBvc2Ugb2YgdGhpcyBkYXRhc2V0IHdhcyB0byBoZWxwIGZpbmQgcHJlZGljdG9ycyBvZiBkaWFiZXRlcy4gVGhlIGdvYWwgaXMgdG8gaGVscCBtZWRpY2FsIHByb2Zlc3Npb25hbHMgaWRlbnRpZnkgcGF0aWVudHMgd2l0aCBwb3RlbnRpYWwgcmlzayBmYWN0b3JzIG9mIGRpYWJldGVzLlRoZSBkYXRhc2V0IGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIHBhdGllbnQgZGVtb2dyYXBoaWNzIHN1Y2ggYXMgYWdlIGFuZCBnZW5kZXIsIGFzIHdlbGwgYXMgbWVkaWNhbCBpbmZvcm1hdGlvbiBpbmNsdWRpbmcgYmxvb2QgZ2x1Y29zZSBsZXZlbHMgYW5kIGh5cGVydGVuc2lvbi4gVGhlIG9ic2VydmF0aW9ucyBpbiB0aGlzIGRhdGFzZXQgd2VyZSBvYnRhaW5lZCBmcm9tIHJlc2VhcmNoIHN0dWRpZXMgYW5kIGhlYWx0aGNhcmUgaW5zdGl0dXRpb25zLiBUaGUgZGF0YXNldCB3YXMgb2J0YWluZWQgdmlhIEthZ2dsZS4gCgpNdXN0YWZhLCBULiBaLiAoMjAyMSkuICpEaWFiZXRlcyBQcmVkaWN0aW9uIERhdGFzZXQqLiBLYWdnbGUuIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvaWFtbXVzdGFmYXR6L2RpYWJldGVzLXByZWRpY3Rpb24tZGF0YXNldAoKVGhlIGRhdGFzZXQgY29uc2lzdHMgb2YgOCBwcmVkaWN0b3IgdmFyaWFibGVzIGZvciBkaWFiZXRlczoKCiogKipnZW5kZXIqKiAtIHRoZSBwYXRpZW50J3MgZ2VuZGVyIGFzIG1hbGUgb3IgZmVtYWxlLgoKKiAqKmFnZSoqIC0gdGhlIGFnZSBvZiB0aGUgcGF0aWVudCBpbiB5ZWFycy4KCiogKipoeXBlcnRlbnNpb24qKiAtIHllcyBvciBubywgb24gd2hldGhlciB0aGUgcGF0aWVudCBoYXMgaHlwZXJ0ZW5zaW9uLgoKKiAqKmhlYXJ0IGRpc2Vhc2UqKiAtIHllcyBvciBubywgb24gd2hldGhlciB0aGUgcGF0aWVudCBoYXMgaGVhcnQgZGlzZWFzZS4KCiogKipzbW9raW5nIGhpc3RvcnkqKiAtIHRoZSBwYXRpZW50J3Mgc21va2luZyBoaXN0b3J5IGluZGljYXRlZCBhcyBuZXZlciwgbm8gaW5mbywgY3VycmVudCwgZm9ybWVyIG9yIG5vdCBjdXJyZW50LgoKKiAqKmJtaSoqIC0gdGhlIHBhdGllbnQncyBib2R5IG1hc3MgaW5kZXggKGtnL20qKjIpLgoKKiAqKkhiQTFjIGxldmVsKiogLSB0aGUgcGF0aWVudCdzIGF2ZXJhZ2UgYmxvb2Qgc3VnYXIgbGV2ZWwgb3ZlciB0aGUgcGFzdCAyLTMgbW9udGhzICglKS4KCiogKipibG9vZCBnbHVjb3NlIGxldmVsKiogLSBhbW91bnQgb2YgYmxvb2Qgc3VnYXIgaW4gdGhlIHBhdGllbnQncyBibG9vZCAobWcvZEwpLgoKCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9J1RoZSBwbG90IG9mIHNob3dzIHRoZSBmcmVxdWVuY3kgb2YgcGF0aWVudHMgd2l0aCBkaWFiZXRlcyBhbmQgaHlwZXJ0ZW5zaW9uLiBUaGUgcGxvdCBpbmRpYWN0ZXMgYSBoaWdoZXIgZnJlcXVlbmN5IG9mIHBhdGllbnRzIG5vdCBoYXZpbmcgZGlhYmV0ZXMgYW5kIG5vdCBoYXZpbmcgaHlwZXJ0ZW5zaW9uLiBUaGVyZSBkb2VzIG5vdCBzZWVtIHRvIGJlIGFuIGludGVyYWN0aW9uIGJldHdlZW4gaGF2aW5nIGRpYWJldGVzIGFuZCBoYXZpbmcgaHlwZXJ0ZW5zaW9uIGJhc2VkIG9uIHRoZSBsb3cgZnJlcXVlbmN5IG9mIHBhdGllbnRzIGhhdmluZyBib3RoLiAnfQojbG9hZCBpbiBkYXRhc2V0CmRhdGEgPC1yZWFkLmNzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dhYmJ5SzgvRGF0YXNldHMvcmVmcy9oZWFkcy9tYWluL2RpYWJldGVzX3ByZWRpY3Rpb25fZGF0YXNldC5jc3YnKQpkaWFiZXRlc2Q8LWRhdGEKCiNjaGFuZ2UgaGVhcnQgZGlzZWFzZSwgZGlhYmV0ZXMgYW5kIGh5cGVydGVuc2lvbiB0byAxIGFuZCAwIGZvciBlYXNpZXIgdXNlIGluIE1JQ0UuCmRhdGEkZGlhYmV0ZXMgPC0gcmVjb2RlKGRhdGEkZGlhYmV0ZXMsICIxIj0iWWVzIiwgIjAiPSJObyIpCmRhdGEkaHlwZXJ0ZW5zaW9uIDwtIHJlY29kZShkYXRhJGh5cGVydGVuc2lvbiwgIjEiPSJZZXMiLCAiMCI9Ik5vIikKZGF0YSRoZWFydF9kaXNlYXNlIDwtIHJlY29kZShkYXRhJGhlYXJ0X2Rpc2Vhc2UsICIxIj0iWWVzIiwgIjAiPSJObyIpCgojcGxvdCBpbnRlcmFjdGlvbiBiZXR3ZWVuIGRpYWJldGVzIGFuZCBoeXBlcnRlbnNpb24uCmdncGxvdChkYXRhLCBhZXMoeCA9IGh5cGVydGVuc2lvbiwgZmlsbCA9IGRpYWJldGVzKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKyAjIFVzZSAic3RhY2siIGZvciBhIHN0YWNrZWQgYmFyIGNoYXJ0CiAgbGFicyAodGl0bGU9IlJpc2sgb2YgRGlhYmV0ZXMgYnkgSHlwZXJ0ZW5zaW9uIiwgeD0iSHlwZXJ0ZW5zaW9uIiwgeT0gIkZyZXF1ZW5jeSIsCiAgICAgICAgZmlsbD0gIkRpYWJldGVzIikKCmBgYAoKIyMgQ29tcGFyaXNvbiBvZiBUd28gQ2F0ZWdvcmljYWwgVmFyaWFibGVzCgpUaGUgcHVycG9zZSBvZiB0aGlzIGdyYXBoIGlzIHRvIHNob3cgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhhdmluZyBoeXBlcnRlbnNpb24gYW5kIGRpYWJldGVzLiBGb3IgdGhpcyBncmFwaCwgSSBjaGFuZ2VkIHRoZSB2YWx1ZXMgb2YgMSBpbiBib3RoIHRoZSBkaWFiZXRlcyBhbmQgaHlwZXJ0ZW5zaW9uIHZhcmlhYmxlIHRvICJZZXMiIGFuZCB0aGUgdmFsdWUgMCB0byAiTm8uIiBUaGVzZSBpbnRlZ2VycyB3ZXJlIG1lYW50IHRvIHJlcHJlc2VudCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgd2l0aCAxIGNvcnJlbGF0aW5nIHRvIGJlaW5nIHBvc2l0aXZlIGZvciBoeXBlcnRlbnNpb24gb3IgZGlhYmV0ZXMgYW5kIDAgY29ycmVsYXRpbmcgdG8gYmVpbmcgbmVnYXRpdmUgdG8gaHlwZXJ0ZW5zaW9uIG9yIGRpYWJldGVzLiBCYXNlZCBvbiBvdXIgZ3JhcGgsIHdlIGNhbiBzZWUgdGhhdCB0aGVyZSBpcyBubyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGhhdmluZyBkaWFiZXRlcyBhbmQgaGF2aW5nIGh5cGVydGVuc2lvbiwgd2l0aCBtb3N0IHBhdGllbnRzIHdpdGhpbiBvdXIgc2FtcGxlIGhhdmluZyBuZWl0aGVyIGRpYWJldGVzIG9yIGh5cGVydGVuc2lvbi4gVGh1cywgaHlwZXJ0ZW5zaW9uIHdvdWxkIG5vdCBiZSBhIGdvb2QgcHJlZGljdG9yIG9mIGRpYWJldGVzIHdpdGhpbiBwYXRpZW50cy4KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgcGxvdCBzaG93cyB0aGUgaW50ZXJhY3Rpb24gYmV0d2VlbiBibG9vZCBnbHVjb3NlIGxldmVscyBhbmQgSGJBMWMgbGV2ZWxzIG9uIGRpYWJldGVzLiBCYXNlZCBvbiB0aGUgcGxvdCwgaGlnaGVyIGJsb29kIGdsdWNvc2UgbGV2ZWxzIGFuZCBIYkExYyBsZXZlbHMgYXJlIHBvc2l0aXZlbHkgY29ycmVsYXRlZCB3aXRoIHRoZSBwcmVzZW5jZSBvZiBkaWFiZXRlcy4gSW4gY29tcGFyaXNvbiwgbG93ZXIgbGV2ZWxzLCBpbmRpY2F0ZSB0aGF0IGEgcGF0aWVudCB3aWxsIG1vcmUgY29tbW9ubHkgbm90IGhhdmUgZGlhYmV0ZXMuIFRoZSBoZWlnaHQgb2YgdGhlIHBvaW50cyBzaG93biBmb3IgZGlhYmV0ZXMgcmVwcmVzZW50IHRoZSBsZXZlbHMgb2YgSGJBMWMsIGJhc2VkIG9uIHRoZSBwbG90LCBIYkExYyBsZXZlbHMgcHJlZGljdCB0aGUgcHJlc2VuY2Ugb2YgZGlhYmV0ZXMgbW9yZSBvZnRlbiB0aGFuIGJsb29kIGdsdWNvc2UgbGV2ZWxzLiAnfQoKCmludGVyYWN0ID0gZ2dwbG90KGRhdGEsIGFlcyh4ID1ibG9vZF9nbHVjb3NlX2xldmVsICwgeSA9IEhiQTFjX2xldmVsLCBncm91cCA9IGRpYWJldGVzLCBjb2xvciA9IGRpYWJldGVzKSkgKwogIGdlb21fbGluZShzaXplID0gMSkgKyAgIyBMaW5lcyByZXByZXNlbnRpbmcgaW50ZXJhY3Rpb24KICBnZW9tX3BvaW50KHNpemUgPSAyKSArICMgUG9pbnRzIGZvciBkYXRhCiAgbGFicygKICAgIHRpdGxlID0gIkludGVyYWN0aW9uIG9mIEJsb29kIEdsdWNvc2UgYW5kIEhiQTFjIExldmVscyIsCiAgICB4ID0gIkJsb29kIEdsdWNvc2UgTGV2ZWwiLAogICAgeSA9ICJIYkExYyBMZXZlbCIsCiAgICBjb2xvciA9ICJQcmVzZW5jZSBvZiBEaWFiZXRlcyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIKICApCmludGVyYWN0CgpgYGAKIyMgQ29tcGFyaXNvbiBvZiBUd28gTnVtZXJpY2FsIFZhcmlhYmxlcwoKVGhlIHR3byB2YXJpYWJsZXMgYmVpbmcgY29tcGFyZWQgaGVyZSBhcmUgQmxvb2QgR2x1Y29zZSBMZXZlbCBhbmQgSGJBMWMgTGV2ZWwuIEhiQTFjYyBpcyBhIHNob3J0ZW5lZCB0ZXJtIGZvciBoZW1vZ2xvYmluIEExYy4gSGIxQWMgbGV2ZWwgaXMgYSBtZWFzdXJlIG9mIGF2ZXJhZ2UgYmxvb2Qgc3VnYXIgbGV2ZWxzIG92ZXIgMi0zIG1vbnRocyBhbmQgaXMgbWVhc3VyZWQgaW4gJS4gQmxvb2QgZ2x1Y29zZSBsZXZlbCBpcyB0aGUgYW1vdW50IG9mIGJsb29kIHN1Z2FyIGluIGEgcGF0aWVudHMgYmxvb2QgYXQgYSBnaXZlbiB0aW1lLiBPdXIgcGxvdCBzaG93cyBhIGNvcnJlbGF0aW9uIGJldHdlZW4gaGlnaCBsZXZlbHMgaW4gSGJBMWMgYW5kIGJsb29kIGdsdWNvc2UgbGV2ZWxzIGFuZCBpdCdzIHJlbGF0aW9uc2hpcCB3aXRoIGRpYWJldGVzLiBUaGlzIHBsb3Qgc3VnZ2VzdHMgcGF0aWVudHMgd2l0aCBoaWdoIGxldmVscyBvZiBIYkExYyBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbHMgYXJlIGF0IGhpZ2ggcmlzayBmb3IgZGlhYmV0ZXMuCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9J1RoZSBib3hwbG90IHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhZ2UgYW5kIHByZXNlbmNlIG9mIGRpYWJldGVzLiBUaGUgYm94cGxvdCBzaG93cyB0aGF0IG9sZGVyIHBhdGllbnRzIG9uIGF2ZXJhZ2UgYXJlIG1vcmUgb2Z0ZW4gaGF2ZSBkaWFiZXRlcy4gVGhlcmUgYXJlIGEgZmV3IG91dGxpZXJzIGluIHRoZSBkaWFiZXRlcyBwb3B1bGF0aW9uIHRoYXQgYXBwZWFyIHRvIGJlIHVuZGVyIHRoZSBhZ2Ugb2YgMjAgeWVhcnMuIFRoaXMgY291bGQgYmUgcmVwcmVzZW50YXRpdmUgb2YgcGF0aWVudHMgd2l0aCBUeXBlIEkgZGlhYmV0ZXMsIHNpbmNlIHRoZSBkYXRhIGRvZXMgbm90IGRpc3Rpbmd1aXNoIGJldHdlZW4gVHlwZSBJIGFuZCBUeXBlIElJIGRpYWJldGVzLiAnfQoKI3Bsb3Qgb2YgYSBudW1lcmljYWwgYW5kIGNhdGVnb3JpY2FsIHZhcmlhYmxlCiBib3hwbG90KGRhdGEkYWdlIH4gZGF0YSRkaWFiZXRlcywKICAgICAgICAgeGxhYj0iUHJlc2VuY2Ugb2YgRGlhYmV0ZXMiLAogICAgICAgICB5bGFiPSJQYXRpZW50IEFnZSIsCiAgICAgICAgIGNvbCA9IGMoInNreWJsdWUiLCAicHVycGxlIiksCiAgICAgICAgIG1haW49IlZpc3VhbGl6YXRpb24gb2YgRGlhYmV0ZXMgYnkgQWdlIiwKICAgICAgICAgY2V4Lm1haW4gPSAxLjEsCiAgICAgICAgIGNvbC5tYWluID0gIm5hdnkiKQpgYGAKCiMjIENvbXBhcmlzb24gb2YgYSBOdW1lcmljYWwgYW5kIENhdGVnb3JpY2FsIFZhcmlhYmxlcwoKVGhpcyBjaGFydCBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYWdlIGFuZCBkaWFiZXRlcyBkaWFnbm9zaXMuIFRoaXMgY2hhcnQgc2hvd3MgdGhhdCBhcyBwYXRpZW50cyBncm93IG9sZGVyIHRoZXkgYXJlIGF0IGhpZ2hlciByaXNrIGZvciBkaWFiZXRlcy4gVGhpcyB3b3VsZCBtYWtlIGFnZSBhIHByZWRpY3RvciBmb3IgZGlhYmV0ZXMsIHdpdGggdGhlIGF2ZXJhZ2UgYWdlIGZvciB0aG9zZSB3aXRob3V0IGRpYWJldGVzIGJlaW5nIDQwIHllYXJzIGFuZCA2MCB5ZWFycyBmb3IgdGhvc2Ugd2l0aCBkaWFiZXRlcy4gSG93ZXZlciwgd2UgY2FuIHNlZSB0aGF0IHdlIGRvIGhhdmUgYSBmZXcgb3V0bGllcnMgZm9yIHRob3NlIHdpdGggZGlhYmV0ZXMgd2l0aCBzb21lIHBhdGllbnRzIGJlaW5nIGRpYWdub3NlZCBhdCAyMCBvciB5b3VuZ2VyLiBUaGlzIGNvdWxkIGJlIGZyb20gdGhlIHBvcHVsYXRpb24gb2YgcGVvcGxlIHdpdGggVHlwZSBJIGRpYWJldGVzIHdoaWNoIGlzIHVzdWFsbHkgZGlhZ25vc2VkIGluIHBhdGllbnRzIHVuZGVyIDIwLiBPdXIgZGF0YXNldCBkb2VzIG5vdCBkaXN0aW5ndWlzaCBiZXR3ZWVuIHR5cGUgSSBhbmQgdHlwZSBJSSBkaWFiZXRlcy4KCgojIENvbmNsdXNpb24gZm9yIENvbXBhcmlzb24gb2YgVmFyaWFibGVzCgpEaWFiZXRlcyBjYW4gYmUgcHJlZGljdGVkIHVzaW5nIGFnZSwgYmxvb2QgZ2x1Y29zZSBsZXZlbHMsIGFuZCBIYkExYyBsZXZlbHMgaW4gcGF0aWVudHMuIEhvd2V2ZXIsIG91ciByZXN1bHRzIHNob3dlZCBoeXBlcnRlbnNpb24gaXMgbm90IGEgZ29vZCBwcmVkaWN0b3Igb2YgZGlhYmV0ZXMuIEJhc2VkIG9uIG91ciBmaW5kaW5ncywgaXQgd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gbG9vayBhdCBmYWN0b3JzIHRoYXQgb2NjdXIgb25jZSBhIHBhdGllbnQgYmVjb21lcyBvbGRlciB0aGF0IGNvdWxkIGxlYWQgdG8gZGlhYmV0ZXMgYXQgYW4gb2xkZXIgYWdlLiBBcyB3ZWxsLCBkaWV0IGNvdWxkIGJlIGFub3RoZXIgZmFjdG9yIHRvIGxvb2sgaW50bywgc3VjaCBhcyBncmFtcyBvZiBzdWdhciBjb25zdW1lZCBvbiBhIGRhaWx5IG9yIHdlZWtseSBiYXNpcywgdG8gc2VlIGlmIHN1Z2FyIGNvbnN1bXB0aW9uIGNhbiBwcmVkaWN0IGRpYWJldGVzLiBBbm90aGVyIGltcG9ydGFudCB0aGluZyB0byBhbmFseXplIGluIGZ1dHVyZSBzdHVkaWVzIHdvdWxkIGJlIFR5cGUgSSB2ZXJzdXMgVHlwZSBJSSBkaWFiZXRlcywgYXMgaXQgY291bGQgYmUgdGhlIHJlYXNvbiBmb3Igc29tZSBvZiB0aGUgb3V0bGllcnMgaW4gdGhlIGJveHBsb3QuIAoKCiMgT3ZlcnZpZXcgb2YgTWlzc2luZyBWYXJpYWJsZXMKCkFuIGltcG9ydGFudCBzdGVwIGluIGRhdGEgYW5hbHlzaXMgZm9yIG1hY2hpbmUgbGVhcm5pbmcgaXMgaGFuZGxpbmcgbWlzc2luZyB2YWx1ZXMuIE1pc3NpbmcgdmFsdWVzIGluIGEgZGF0YXNldCBjYW4gb2NjdXIgZm9yIG1hbnkgcmVhc29ucywgYnV0IG5vdCBsaW1pdGVkIHRvIG5vbi1yZXNwb25zZSBpbiBzdXJ2ZXlzLCBwYXJ0aWNpcGFudHMgbGVhdmluZyB0aGUgc3R1ZHksIGRhdGEgZW50cnkgZXJyb3JzIGFuZCBzeXN0ZW0gbGltaXRhdGlvbnMuIElmIG1pc3NpbmcgdmFsdWVzIGFyZSBub3QgYWRkcmVzc2VkLCBtb2RlbHMgY2FuIGJlY29tZSBiaWFzZWQgYW5kIGFjY3VyYWN5IG9mIHRoZSBhbmF5bHlzaXMgY2FuIGRlY3JlYXNlLiBUaGlzIHNlY3Rpb24gZXhhbWluZXMgZGlmZmVyZW50IGltcHV0YXRpb24gc3RyYXRlZ2llcyB0byBlZmZlY3RpdmVseSBoYW5kbGUgbWlzc2luZyB2YWx1ZXMuCgpUaGUgaW1wdXRhdGlvbiBtZXRob2RzIHdlIHdpbGwgZXhhbWluZSBpbmNsdWRlOgoKUmVwbGFjZW1lbnQgSW1wdXRhdGlvbiBmb3IgQ2F0ZWdvcmljYWwgRmVhdHVyZXM6IE1vZGUgaW1wdXRhdGlvbi4KClJlZ3Jlc3Npb24tYmFzZWQgSW1wdXRhdGlvbiBmb3IgTnVtZXJpY2FsIEZlYXR1cmVzOiBQcmVkaWN0aXZlIG1vZGVsaW5nIHRvIGVzdGltYXRlIG1pc3NpbmcgdmFsdWVzLgoKTXVsdGlwbGUgSW1wdXRhdGlvbjogQWR2YW5jZWQgbWV0aG9kcyBzdWNoIGFzIE1JQ0UgdG8gaW1wcm92ZSByb2J1c3RuZXNzLgoKYGBge3J9CiMgY3JlYXRlIHJhbmRvbSBvYnNlcnZhdGlvbiBJRCBhbmQgcmVwbGFjZSB0aGUgY29ycmVzcG9uZGluZyBvYnMgd2l0aCBtaXNzaW5nCmx0ci5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDUwLCByZXBsYWNlID0gRkFMU0UpCmdwYS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDE1LCByZXBsYWNlID0gRkFMU0UpIApkaWFiZXRlc2QkYm1pW2x0ci5taXNzaW5nLmlkXSA8LSBOQQpkaWFiZXRlc2QkaGVhcnRfZGlzZWFzZVtncGEubWlzc2luZy5pZF0gPC0gTkEKZGlhYmV0ZXNkJHNtb2tpbmdfaGlzdG9yeVtkaWFiZXRlc2Qkc21va2luZ19oaXN0b3J5ID09ICJObyBJbmZvIl0gPC0gTkEKCmBgYAoKIyMgTW9kZSBJbXB1dGF0aW9uIGZvciBDYXRlZ29yaWNhbCBWYXJpYWJsZXMKCkluIHRoaXMgbWV0aG9kLCBtaXNzaW5nIHZhcmlhYmxlcyBhcmUgcmVwbGFjZWQgd2l0aCB0aGUgbW9zdCBmcmVxdWVudCBjYXRlZ29yeSBvZiB0aGUgY29ycmVzcG9uZGluZyB2YXJpYWJsZS4gTW9kZSBpbXB1dGF0aW9uIGVuc3VyZXMgY29uc2lzdGVuY3kgYW5kIHdvcmtzIHdlbGwgd2hlbiBtaXNzaW5nIHZhbHVlcyBhcmUgcmFuZG9tbHkgZGlzdHJpYnV0ZWQuIEJlbG93LCBtb2RlIGltcHV0YXRpb24gaXMgdXNlZCBvbiB0aGUgdmFyaWFibGUsIGhlYXJ0IGRpc2Vhc2UsIHdoaWNoIGlzIDEgaWYgdGhlIHBhdGllbnQgaGFzIGhlYXJ0IGRpc2Vhc2UgYW5kIDAgaWYgdGhlIHBhdGllbnQgZG9lcyBub3QgaGF2ZSBoZWFydCBkaXNlYXNlLlRoZSB2YXJpYWJsZSBzbW9raW5nIGhpc3RvcnkgaGFkIGN1cnJlbnQsIGZvcm1lciwgbm8gaW5mbywgbmV2ZXIsIGFuZCBldmVyIGFzIHBvc3NpYmxlIHZhbHVlcy4gTm8gSW5mbyBpbmRpY2F0ZXMgdGhhdCB3ZSBkbyBub3QgaGF2ZSBpbmZvcm1hdGlvbiBvbiB0aGUgcGFydGljaXBhbnQncyBzbW9raW5nIGhpc3RvcnkgYW5kIHdpbGwgYmUgdHJlYXRlZCBhcyBhIG1pc3NpbmcgdmFsdWVzLgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgcGxvdCBzaG93cyB0aGUgY29tcGFyaXNvbiBiZXR3ZWVuIHRoZSBvcmlnaW5hbCBkYXRhIGNvbnRhaW5pbmcgbWlzc2luZyB2YWx1ZXMgZm9yIHRoZSB2YXJpYWJsZXMgaGVhcnQgZGlzZWFzZSBhbmQgc21va2luZyBoaXN0b3J5LCBhbmQgdGhlIGRhdGEgYWZ0ZXIgdXNpbmcgbW9kZSBpbXB1dGUuIFRoZSBoaXN0b2dyYW1zIHNob3cgdGhhdCBtb2RlIGltcHV0ZSB1c2VkIHdoYXQgd2FzIG1vc3QgY29tbW9uIHRvIHJlcGxhY2UgdGhlIG1pc3NpbmcgdmFsdWVzLiBUaGlzIGlzIHNlZW4gY2xlYXJseSBpbiB0aGUgdmFyaWFibGUgc21va2luZyBoaXN0b3J5LCB3aGVyZSB0aGUgY2F0ZWdvcnkgbmV2ZXIgd2VudCBmcm9tIG9yaWdpbmFsbHkgYSBjb3VudCBvZiBhYm91dCA0MCwwMDAgdG8gYWJvdXQgNzAsMDAwLiBIZWFydCBkaXNlYXNlIGhhZCBhIHNtYWxsIGFtb3VudCBvZiBtaXNzaW5nIGRhdGEgKG9ubHkgMTUpLCBob3dldmVyIHRoZSAxNSBtaXNzaW5nIHdlcmUgY2hhbmdlZCB0byAwLCBpbmRpY2F0aW5nIHRoZSBwYXRpZW50IHdvdWxkIG5vdCBoYXZlIGhlYXJ0IGRpc2Vhc2UuJywgZWNobz1GQUxTRX0KCgpkaWFiZXRlc2QgPC1kaWFiZXRlc2QKIyBGdW5jdGlvbiB0byBpbXB1dGUgbW9kZQoKTW9kZSA8LSBmdW5jdGlvbih4KSB7CiAgdXggPC0gdW5pcXVlKG5hLm9taXQoeCkpICAjIFJlbW92ZSBOQXMgYmVmb3JlIGNvbXB1dGluZyBtb2RlCiAgdGFiIDwtIHRhYnVsYXRlKG1hdGNoKHgsIHV4KSkKICBtb2RlX3ZhbHVlIDwtIHV4W3doaWNoLm1heCh0YWIpXQogIAogICMgRW5zdXJlIG1vZGVfdmFsdWUgaXMgb2YgdGhlIHNhbWUgdHlwZSBhcyB4CiAgaWYgKGlzLmZhY3Rvcih4KSkgewogICAgcmV0dXJuKGZhY3Rvcihtb2RlX3ZhbHVlLCBsZXZlbHMgPSBsZXZlbHMoeCkpKQogIH0gZWxzZSBpZiAoaXMuY2hhcmFjdGVyKHgpKSB7CiAgICByZXR1cm4oYXMuY2hhcmFjdGVyKG1vZGVfdmFsdWUpKQogIH0gZWxzZSB7CiAgICByZXR1cm4oYXMubnVtZXJpYyhtb2RlX3ZhbHVlKSkKICB9Cn0KI2FwcGx5IG1vZGUgaW1wdXRhdGlvbgp2YWx1ZV9pbXB1dGVkIDwtIGRhdGEuZnJhbWUoCiAgb3JpZ2luYWwgPSBkaWFiZXRlc2QkaGVhcnRfZGlzZWFzZSwKICBvcmlnaW5hbDI9ZGlhYmV0ZXNkJHNtb2tpbmdfaGlzdG9yeSwKICBpbXB1dGVkX21vZGVoZCA9IHJlcGxhY2UoZGlhYmV0ZXNkJGhlYXJ0X2Rpc2Vhc2UsIGlzLm5hKGRpYWJldGVzZCRoZWFydF9kaXNlYXNlKSwgTW9kZSgoZGlhYmV0ZXNkJGhlYXJ0X2Rpc2Vhc2UpKSksCiAgaW1wdXRlZF9tb2Rlc2ggPSByZXBsYWNlKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnksIGlzLm5hKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnkpLCBNb2RlKGRpYWJldGVzZCRzbW9raW5nX2hpc3RvcnkpKSkKc3VtbWFyeSh2YWx1ZV9pbXB1dGVkKQoKI3Bsb3QgdGhlIGNvbXBhcmlzb24gb2Ygb3JpZ2luYWwgZGF0YSBhbmQgbW9kZSBpbXB1dGVkIGRhdGEKaDEgPC0gZ2dwbG90KHZhbHVlX2ltcHV0ZWQsIGFlcyh4ID0gb3JpZ2luYWwpKSArCiAgZ2VvbV9iYXIoYmlucz0xMCwgZmlsbCA9ICIjYWQxNTM4IiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk9yaWdpbmFsIGZvciBIZWFydCBEaXNlYXNlIikgKwogIHRoZW1lX2NsYXNzaWMoKQpoMiA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBvcmlnaW5hbDIpKSArCiAgZ2VvbV9iYXIoIGZpbGwgPSAiIzE1YWQ0ZiIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCBmb3IgU21va2luZyBIaXN0b3J5IikgKwogIHRoZW1lX2NsYXNzaWMoKQpoMyA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBpbXB1dGVkX21vZGVoZCkpICsKICBnZW9tX2JhcihiaW5zPTEwLCBmaWxsID0gIiMxNTQzYWQiLCBjb2xvciA9ICIjMDAwMDAwIiwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArCiAgZ2d0aXRsZSgiTW9kZS1pbXB1dGVkIGZvciBIZWFydCBEaXNlYXNlIikgKwogIHRoZW1lX2NsYXNzaWMoKQpoNCA8LSBnZ3Bsb3QodmFsdWVfaW1wdXRlZCwgYWVzKHggPSBpbXB1dGVkX21vZGVzaCkpICsKICBnZW9tX2JhciggZmlsbCA9ICIjYWQ4NDE1IiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk1vZGUtaW1wdXRlZCBmb3IgU21va2luZyBIaXN0b3J5IikgKwogIHRoZW1lX2NsYXNzaWMoKQoKCnBsb3RfZ3JpZChoMSwgaDIsIGgzLCBoNCwgbnJvdyA9IDIsIG5jb2wgPSAyKQoKCgpgYGAKCiMjIFJlZ3Jlc3Npb24tQmFzZWQgSW1wdXRhdGlvbiBmb3IgTnVtZXJpY2FsIFZhcmlhYmxlcwoKVXNpbmcgcmVncmVzc2lvbiBtb2RlbHMsIHdlIGNhbiBlc3RpbWF0ZSBtaXNzaW5nIHZhbHVlcy4gRm9yIHRoZSB2YXJpYWJsZSwgYm1pLCB3ZSBjYW4gcHJlZGljdCB0aGUgbWlzc2luZyB2YWx1ZXMgdXNpbmcgZXN0aW1hdGVzIGZyb20gb3VyIG1vZGVsLiBCbWkgaXMgYSBjb250aW51b3VzIHZhcmlhYmxlLCB1bmxpa2UgdGhlIHByZXZpb3VzIGV4YW1wbGUgd2hlcmUgb3VyIHZhbHVlcyBjb3VsZCBvbmx5IGJlIDAgb3IgMS4gSW4gdGhpcyBtZXRob2QsIGEgbGluZWFyIG1vZGVsIHdhcyBjcmVhdGVkIHRvIGhlbHAgY3JlYXRlIGVzdGltYXRlcyBvZiBvdXIgdmFsdWVzLiAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nVGhlIGJveHBsb3RzIHNob3cgdGhlIGNvbXBhcmlzb24gb2YgdGhlIHZhcmlhYmxlIGJtaSBiZWZvcmUgYW5kIGFmdGVyIHJlZ3Jlc3Npb24gaW1wdXRhdGlvbi4nIH0KCiNjcmVhdGUgYSBkYXRhc2V0IGZvciByZWdyZXNzaW9uIGltcHV0ZQpyZWdpbXB1dGU8LWRpYWJldGVzZAoKIyBJZGVudGlmeSByb3dzIHdoZXJlIEJNSSBpcyBtaXNzaW5nCm1pc3Npbmdfcm93cyA8LSB3aGljaChpcy5uYShkaWFiZXRlc2QkYm1pKSkgICMgR2V0IHJvdyBpbmRpY2VzCgoKIyBUcmFpbiBhIGxpbmVhciBtb2RlbCB1c2luZyBjb21wbGV0ZSBjYXNlcwpsbV9tb2RlbCA8LSBsbShibWkgfiBhZ2UgKyBibG9vZF9nbHVjb3NlX2xldmVsICsgSGJBMWNfbGV2ZWwgKyBoZWFydF9kaXNlYXNlICsgaHlwZXJ0ZW5zaW9uICsgZGlhYmV0ZXMsIAogICAgICAgICAgICAgICBkYXRhID0gcmVnaW1wdXRlLCBuYS5hY3Rpb24gPSBuYS5leGNsdWRlKQoKIyBJbXB1dGUgbWlzc2luZyBCTUkgdmFsdWVzIHVzaW5nIHRoZSBtb2RlbApkaWFiZXRlc2QkYm1pW21pc3Npbmdfcm93c10gPC0gcHJlZGljdChsbV9tb2RlbCwgbmV3ZGF0YSA9IHJlZ2ltcHV0ZVttaXNzaW5nX3Jvd3MsIF0pCgoKZGVwLm1pIDwtIGJpbmRfcm93cygKICBkYXRhLmZyYW1lKHZhbHVlID0gZGlhYmV0ZXNkJGJtaSwgaW1wdXRlZCA9IHJlZ2ltcHV0ZSRibWkpKQogICAgICAgICAgICAgI2ltcCA9ICJkZXAuaW1wMSIpCgoKaTc8LWJveHBsb3QoZGlhYmV0ZXNkJGJtaSwKbWFpbiA9ICJNZWFuIGJtaSBpbiBPcmlnaW5hbCBEYXRhIiwKeGxhYiA9ICJCTUkiLApjb2wgPSAiYmx1ZSIsCmJvcmRlciA9ICJibGFjayIsCmhvcml6b250YWwgPSBUUlVFLApub3RjaCA9IFRSVUUKKQppOCA8LWJveHBsb3QocmVnaW1wdXRlJGJtaSwKbWFpbiA9ICJSZWdyZXNzaW9uIEltcHV0YXRpb24gZm9yIEJNSSIsCnhsYWIgPSAiQk1JIiwKY29sID0gInJlZCIsCmJvcmRlciA9ICJibGFjayIsCmhvcml6b250YWwgPSBUUlVFLApub3RjaCA9IFRSVUUKKQoKCiAKCmBgYAoKIyMgTUlDRSBJbXB1dGF0aW9uCgpNSUNFIGlzIG11bHRpcGxlIGltcHV0YXRpb24gdGVjaG5pcXVlcyB1c2VkIHRvIGltcHV0ZSBtaXNzaW5nIHZhbHVlcy4gVGhpcyBtZXRob2QgYWxzbyB1c2VzIHJlZ3Jlc3Npb24gbW9kZWxzIGFuZCBhY2NvdW50cyBmb3IgdW5jZXJ0YWludHkgYnkgZ2VuZXJhdGluZyBtdWx0aXBsZSBwb3NzaWJsZSB2YWx1ZXMuIFVzaW5nIE1JQ0UsIHRoZSB2YXJpYWJsZXMgc21va2luZyBoaXN0b3J5LCBoZWFydCBkaXNlYXNlLCBhbmQgYm1pLCBjYW4gYmUgaW1wdXRhdGVkIHdpdGhpbiBvbmUgZnVuY3Rpb24uIE1JQ0UgY2FuIGhhbmRsZSBkaWZmZXJlbnQgdHlwZXMgb2YgdmFyaWFibGVzLCBpbXB1dGF0ZXMgYmFzZWQgb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhYmxlcyBhbmQgaXQgYWNjb3VudHMgZm9yIHZhcmlhYmlsaXR5IGluIG1pc3NpbmcgZGF0YS4gCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nQmFzZWQgb24gdGhlIHRocmVlIGdyYXBocywgTUlDRSBzZWVtcyB0byBoYXZlIHByb2R1Y2VkIHZhbHVlcyB0aGF0IGFwcGVhciBhbG1vc3QgaWRlbnRpY2FsIHRvIHRoZSBvcmlnaW5hbCBkYXRhc2V0LiBNb2RlIGltcHV0ZSBzZWVtcyB0byBiZSBzbGlnaHRseSBkaWZmZXJlbnQgc2luY2UgaXQgcmVsaWVzIG9uIGZpbGxpbmcgbWlzc2luZyB2YWx1ZXMgd2l0aCB0aGUgbW9zdCBjb21tb24gdmFsdWUuIEluIHRoaXMgY2FzZSwgbW9kZSBpbXB1dGUgZmlsbGVkIGFsbCBtaXNzaW5nIHZhbHVlcyBhcyAwIGFuZCB1bmRlci1yZXByZXNlbnRlZCAxLicsIGVjaG89RkFMU0V9CgojcmVsb2FkIGRhdGFzZXQgc28gdGhhdCBpdCBpcyBmcmVlIG9mIG1vZGUgYW5kIHJlZ3Jlc3Npb24gaW1wdXRhdGlvbiBkb25lIHByZXZpb3VzbHkKZGF0YTIgPC0gcmVhZC5jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HYWJieUs4L0RhdGFzZXRzL3JlZnMvaGVhZHMvbWFpbi9kaWFiZXRlc19wcmVkaWN0aW9uX2RhdGFzZXQuY3N2JykKCiNjcmVhdGUgbWlzc2luZyB2YWx1ZXMgYW5kIG1ha2Ugc21va2luZyBoaXN0b3J5IGEgYmluYXJ5IHZhcmlhYmxlCmx0ci5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDUwLCByZXBsYWNlID0gRkFMU0UpCmdwYS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDE1LCByZXBsYWNlID0gRkFMU0UpIApkYXRhMiRzbW9raW5nX2hpc3RvcnlbZGF0YTIkc21va2luZ19oaXN0b3J5PT0gIk5vIEluZm8iXSA8LU5BCmRhdGEyJGJtaVtsdHIubWlzc2luZy5pZF0gPC0gTkEKZGF0YTIkaGVhcnRfZGlzZWFzZVtncGEubWlzc2luZy5pZF0gPC0gTkEKCiNtYWtlIHZhcmlhYmxlcyBudW1lcmljCmRhdGEyJGdlbmRlciA8LSBhcy5udW1lcmljKGFzLmZhY3RvcihkYXRhMiRnZW5kZXIpKQpkYXRhMiRoZWFydF9kaXNlYXNlPC0gYXMuZmFjdG9yKGFzLm51bWVyaWMoZGF0YTIkaGVhcnRfZGlzZWFzZSkpCmRhdGEyJHNtb2tpbmdfaGlzdG9yeTwtYXMuZmFjdG9yKGRhdGEyJHNtb2tpbmdfaGlzdG9yeSkKI2FwcGx5IE1JQ0UgaW1wdXRhdGlvbgpkZl9taWNlIDwtIG1pY2UoZGF0YTIsIG1ldGhvZCA9IGMoIiIsIiIsIiIsInBtbSIsInBvbHlyZWciLCJwbW0iLCIiLCIiLCIiKSwgIG0gPSAyMCwgbWF4aXQ9MjAsc2VlZCA9IDEyMywgcHJpbnQ9RikKCiMgQ29tcGxldGUgZGF0YXNldCB3aXRoIGltcHV0ZWQgdmFsdWVzCmRmX2ltcHV0ZWQgPC0gY29tcGxldGUoZGZfbWljZSkKCiNwbG90IGNvbXBhcmlzb25zIG9mIGJlZm9yZSBhbmQgYWZ0ZXIgTUlDRSBpbXB1dGF0aW9uIGZvciBoZWFydCBkaXNlYXNlCmcxIDwtIGdncGxvdCh2YWx1ZV9pbXB1dGVkLCBhZXMoeCA9IGltcHV0ZWRfbW9kZWhkKSkgKwogIGdlb21fYmFyKGZpbGwgPSAiIzE1NDNhZCIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJNb2RlLWltcHV0ZWQiKSArCiAgbGFicyh4PSJIZWFydCBEaXNlYXNlIikrCiAgdGhlbWVfY2xhc3NpYygpCmcyIDwtIGdncGxvdCh2YWx1ZV9pbXB1dGVkLCBhZXMoeCA9IG9yaWdpbmFsKSkgKwogIGdlb21fYmFyKGZpbGwgPSAiI2FkMTUzOCIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCIpICsKICBsYWJzKHg9IkhlYXJ0IERpc2Vhc2UiKSsKICB0aGVtZV9jbGFzc2ljKCkKZzMgPC0gZ2dwbG90KGRmX2ltcHV0ZWQsIGFlcyh4ID0gaGVhcnRfZGlzZWFzZSkpICsKICBnZW9tX2JhcihmaWxsID0gInB1cnBsZSIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJNSUNFIikgKwogIGxhYnMoeD0iSGVhcnQgRGlzZWFzZSIpKwogIHRoZW1lX2NsYXNzaWMoKQpwbG90X2dyaWQoZzEsIGcyLCBnMywgbnJvdz0xLCBuY29sID0zKQpgYGAKCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0gJ1RoZSBiYXIgZ3JhcGhzIHNob3cgdGhlIGNvbXBhcmlzb24gb2YgdGhlIG9yaWdpbmFsIGRhdGEgdG8gbW9kZSBpbXB1dGF0aW9uIGFuZCBNSUNFLiBNSUNFIGFwcGVhcnMgdG8gaGF2ZSBkaXNwZXJzZWQgdGhlIGRhdGEgbW9yZSBldmVubHkgYWNyb3NzIHRoZSBkaWZmZXJlbnQgY2F0ZWdvcmllcywgd2hpbGUgbW9kZSBpbXB1dGF0aW9uIGhhcyBvbmx5IGFkZGVkIHZhbHVlcyB0byB0aGUgY2F0ZWdvcnkgbmV2ZXIuJ30KI3Bsb3QgY29tcGFyaXNvbnMgZm9yIHNtb2tpbmcgaGlzdG9yeQpnNCA8LSBnZ3Bsb3QoZGZfaW1wdXRlZCwgYWVzKHggPSBzbW9raW5nX2hpc3RvcnkpKSArCiAgZ2VvbV9iYXIoIGZpbGwgPSAicHVycGxlIiwgY29sb3IgPSAiIzAwMDAwMCIsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIk1JQ0UiKSArCiAgbGFicyh4PSJTbW9raW5nIEhpc3RvcnkiKSsKICB0aGVtZV9jbGFzc2ljKCkKZzUgPC0gZ2dwbG90KHZhbHVlX2ltcHV0ZWQsIGFlcyh4ID0gb3JpZ2luYWwyKSkgKwogIGdlb21fYmFyKCBmaWxsID0gInJlZCIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCBTbW9raW5nIEhpc3RvcnkiKSArCiAgbGFicyh4PSJTbW9raW5nIEhpc3RvcnkiKSsKICB0aGVtZV9jbGFzc2ljKCkKZzYgPC0gZ2dwbG90KHZhbHVlX2ltcHV0ZWQsIGFlcyh4ID0gaW1wdXRlZF9tb2Rlc2gpKSArCiAgZ2VvbV9iYXIoIGZpbGwgPSAiYmx1ZSIsIGNvbG9yID0gIiMwMDAwMDAiLCBwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJNb2RlLWltcHV0ZWQiKSArCiAgbGFicyh4PSJTbW9raW5nIEhpc3RvcnkiKSsKICB0aGVtZV9jbGFzc2ljKCkKcGxvdF9ncmlkKGc0LGc1LGc2LCBucm93PTMsIG5jb2w9MSkKYGBgCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcD0nVGhlIGJveHBsb3RzIHNob3cgdGhlIGNvbXBhcmlzb24gb2YgdGhlIG9yaWdpbmFsIGRhdGEgdG8gYm90aCBNSUNFIGFuZCByZWdyZXNzaW9uIGltcHV0YXRpb24uIFRoZSBhcHBlYXIgdG8gaGF2ZSBzaW1pbGFyIHJlc3VsdHMsIGJhc2VkIG9uIG1lYW4gd2hpY2ggaXMgaW5kaWNhdGVkIGJ5IHRoZSBibGFjayBsaW5lIHdpdGhpbiBlYWNoIGJveC4nfQoKI3Bsb3QgY29tcGFyaXNvbnMgZm9yIGJtaQpnNzwtYm94cGxvdChkaWFiZXRlc2QkYm1pLAptYWluID0gIk1lYW4gQk1JIGluIE9yaWdpbmFsIERhdGEiLAp4bGFiID0gIkJNSSIsCmNvbCA9ICJibHVlIiwKYm9yZGVyID0gImJsYWNrIiwKaG9yaXpvbnRhbCA9IFRSVUUsCm5vdGNoID0gVFJVRQopCmc4IDwtYm94cGxvdChyZWdpbXB1dGUkYm1pLAptYWluID0gIlJlZ3Jlc3Npb24gSW1wdXRhdGlvbiBmb3IgQk1JIiwKeGxhYiA9ICJCTUkiLApjb2wgPSAicmVkIiwKYm9yZGVyID0gImJsYWNrIiwKaG9yaXpvbnRhbCA9IFRSVUUsCm5vdGNoID0gVFJVRQopCmc5IDwtYm94cGxvdChkZl9pbXB1dGVkJGJtaSwKbWFpbiA9ICJNSUNFIGZvciBCTUkiLAp4bGFiID0gIkJNSSIsCmNvbCA9ICJwdXJwbGUiLApib3JkZXIgPSAiYmxhY2siLApob3Jpem9udGFsID0gVFJVRSwKbm90Y2ggPSBUUlVFCikKCgoKYGBgCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTV9Cm1vZGVsNSA8LSB3aXRoKGRmX21pY2UsIGxtKGRpYWJldGVzIH4gYm1pKyBoZWFydF9kaXNlYXNlKyBzbW9raW5nX2hpc3RvcnkgKSkKc3VtbWFyeShwb29sKG1vZGVsNSkpIAoKCmBgYAoKVGhlIHN0YXRpc3RpY3MgYWJvdmUgc2hvdyB0aGUgc3VtbWFyeSBvZiB0aGUgbmV3bHkgaW1wdXRlZCBtaXNzaW5nIHZhcmlhYmxlcyB0aHJvdWdoIE1JQ0UuIEJhc2VkIG9uIG91ciBwLXZhbHVlcywgc21va2luZyBoaXN0b3J5IHdpbGwgbW9zdCBsaWtlbHkgbm90IGJlIGNob3NlbiBmb3IgdGhlIGZpbmFsIG1vZGVsIGFzIGl0J3Mgc2lnbmlmaWNhbmNlIGxldmVsIGlzIGdyZWF0ZXIgdGhhbiAwLjA1LCBpbmRpY2F0aW5nIGFuIGluc2lnbmlmaWNhbnQgcHJlZGljdG9yIHZhcmlhYmxlLiAKCgojIFNrZXduZXNzCgpTa2V3bmVzcyBpcyBhIG1lYXN1cmUgb2Ygc3ltbWV0cnkgd2l0aGluIGEgZGlzdHJpYnV0aW9uLiBUaGUgc2tld25lc3MgbWVhc3VyZW1lbnRzIGJlbG93IGFyZSBvZiB0aGUgdmFyaWFibGVzIGFnZSwgYm1pLCBIYkExYyBsZXZlbCwgYW5kIGJsb29kIGdsdWNvc2UgbGV2ZWwsIHJlc3BlY3RpdmVseS4gV2hlbiBza2V3bmVzcyBpcyBlcXVhbCB0byAwLCB3ZSBjYW4gYXNzdW1lIHRoZSBkYXRhIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBXaGVuIHNrZXduZXNzIGlzIGdyZWF0ZXIgdGhhbiAwLCBvdXIgZGF0YSBpcyBwb3NpdGl2ZWx5IHNrZXdlZCwgd2hpbGUgYSB2YWx1ZSBsZXNzIHRoYW4gemVybyBpbmRpY2F0ZXMgbmVnYXRpdmVseSBza2V3ZWQgZGF0YS4gRm9yIHRoZSBkaWFiZXRlcyBkYXRhc2V0LCB0aGUgdmFyaWFibGVzIGJtaSBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbCBhcmUgMSBvciBhYm91dCAxLCB3aGljaCBpbmRpY2F0ZSBhIHNpZ25pZmljYW50IHJpZ2h0IHNrZXcgaW4gdGhlIGRpc3RyaWJ1dGlvbi4gCmBgYHtyfQoKCgphZ2UxPC0gc2tld25lc3MoZGZfaW1wdXRlZCRhZ2UpIApibWkxPC1za2V3bmVzcyhkZl9pbXB1dGVkJGJtaSkgCkhiQTFjMTwtc2tld25lc3MoIGRmX2ltcHV0ZWQkSGJBMWNfbGV2ZWwpIApnbHVjb3NlMTwtc2tld25lc3MoZGZfaW1wdXRlZCRibG9vZF9nbHVjb3NlX2xldmVsKQoKbXl0YWJsZTwtZGF0YS5mcmFtZShhZ2UxLGJtaTEsSGJBMWMxLCBnbHVjb3NlMSkKcGFuZGVyKG15dGFibGUsIGNhcHRpb249ICJTa2V3bmVzcyBvZiBOdW1lcmljIFZhcmlhYmxlcyIscG9zaXRpb249ImNlbnRlciIpCgpgYGAKCgoKCiMgVHJhbnNmb3JtaW5nIERhdGEKClRvIGhhbmRsZSBvdXIgc2tld2VkIHZhcmlhYmxlcywgd2UgY2FuIG5vcm1hbGl6ZSB0aGUgdmFyaWFibGVzIGJtaSBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbC4gTm9ybWFsaXphdGlvbiByZXNjYWxlcyBkYXRhIGludG8gYSBmaXhlZCByYW5nZSBvZiBbMCwxXS4gQnkgbm9ybWFsaXppbmcgb3VyIGRhdGEsIHdlIGNhbiBmaXggc2tld25lc3MgYW5kIGNyZWF0ZSBub3JtYWxseSBkaXN0cmlidXRlZCBkYXRhLiBUaGUgdmFyaWFibGVzLCBhZ2UgYW5kIEhiQTFjIGxldmVsIGhhdmUgYmVlbiBzdGFuZGFyZGl6ZWQgdG8ga2VlcCB0aGUgZGlzdHJpYnV0aW9uIGNlbnRlcmVkLiBTdGFuZGFyZGl6YXRpb24gaXMgdXNlZCB0byBjcmVhdGUgYSBtZWFuIG9mIDAgYW5kIGEgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIDEsIHRvIGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24uIEJhc2VkIG9uIHRoZSByZXN1bHRzIGJlbG93LCB3ZSBjYW4gc2VlIHRoYXQgdGhlIHRyYW5zZm9ybWF0aW9uIGhhcyBjb3JyZWN0ZWQgdGhlIHJpZ2h0IHNrZXcgaW4gdGhlIGRhdGEgZnJvbSBiZWZvcmUuCgoKYGBge3J9CmRmX3RyYW5zIDwtIGRmX2ltcHV0ZWQgICMgQ29weSBvcmlnaW5hbCBkYXRhc2V0IGFmdGVyIE1JQ0UKCiNlbnN1cmUgZGlhYmV0ZXMgaXMgbnVtZXJpYyBhbmQgYSBmYWN0b3IKZGZfdHJhbnMkZGlhYmV0ZXM8LSBhcy5udW1lcmljKGFzLmZhY3RvcihkZl90cmFucyRkaWFiZXRlcykpCiMgTWluLU1heCBOb3JtYWxpemF0aW9uCm5vcm1hbGl6ZSA8LSBmdW5jdGlvbih4KSB7CiAgaWYgKG1heCh4KSAtIG1pbih4KSA9PSAwKSByZXR1cm4ocmVwKDAsIGxlbmd0aCh4KSkpICAjIFByZXZlbnQgZGl2aXNpb24gYnkgemVybwogIHJldHVybigoeCAtIG1pbih4KSkgLyAobWF4KHgpIC0gbWluKHgpKSkKfQoKI2FwcGx5IG5vcm1hbGl6YXRpb24KZGZfdHJhbnMkYm1pIDwtIG5vcm1hbGl6ZShkZl9pbXB1dGVkJGJtaSkKZGZfdHJhbnMkYmxvb2RfZ2x1Y29zZV9sZXZlbCA8LSBub3JtYWxpemUoZGZfaW1wdXRlZCRibG9vZF9nbHVjb3NlX2xldmVsKQoKIyBaLVNjb3JlIFN0YW5kYXJkaXphdGlvbgpzdGFuZGFyZGl6ZSA8LSBmdW5jdGlvbih4KSB7CiAgcmV0dXJuKCh4IC0gbWVhbih4LCBuYS5ybSA9IFRSVUUpKSAvIHNkKHgsIG5hLnJtID0gVFJVRSkpCn0KCiNhcHBseSBzdGFuZGFyZGl6YXRpb24KZGZfdHJhbnMkYWdlIDwtIHN0YW5kYXJkaXplKGRmX3RyYW5zJGFnZSkKZGZfdHJhbnMkSGJBMWNfbGV2ZWwgPC0gc3RhbmRhcmRpemUoZGZfdHJhbnMkSGJBMWNfbGV2ZWwpCgojIEFwcGx5IExvZyBUcmFuc2Zvcm1hdGlvbiB0byBGaXggU2tld25lc3MgKGlmIG5lY2Vzc2FyeSkKZGZfdHJhbnMkYm1pIDwtIGxvZzFwKGRmX3RyYW5zJGJtaSkgICMgbG9nKDEgKyB4KSBhdm9pZHMgbG9nKDApIGlzc3VlcwpkZl90cmFucyRibG9vZF9nbHVjb3NlX2xldmVsIDwtIGxvZzFwKGRmX3RyYW5zJGJsb29kX2dsdWNvc2VfbGV2ZWwpCgpibWkyIDwtIHNrZXduZXNzKGRmX3RyYW5zJGJtaSkKYWdlMiA8LSBza2V3bmVzcyhkZl90cmFucyRhZ2UpCkhiQTFjMjwtIHNrZXduZXNzKGRmX3RyYW5zJEhiQTFjX2xldmVsKQpnbHVjb3NlMjwtIHNrZXduZXNzKGRmX3RyYW5zJGJsb29kX2dsdWNvc2VfbGV2ZWwpCgpuZXd0YWJsZTwtZGF0YS5mcmFtZShibWkyLGFnZTIsSGJBMWMyLGdsdWNvc2UyKQpwYW5kZXIobmV3dGFibGUsIGNhcHRpb249Ik5ld2x5IFRyYW5zZm9ybWVkIERhdGEiLCBwb3NpdGlvbj0iY2VudGVyIikKCgpgYGAKClRyYW5zZm9ybWluZyBvdXIgZGF0YSBoYXMgc3VjY2Vzc2Z1bGx5IGRlY3JlYXNlZCBza2V3bmVzcyBpbiBvdXIgdmFyaWFibGVzLiBXZSBjYW4gc2VlIGJtaSBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbCBhcmUgbm8gbG9uZ2VyIGFib3V0IDEuIAoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdXZSBjYW4gc2VlIGluIHRoZSBncmFwaHMgYWJvdmUgdGhhdCBhZnRlciB0cmFuc2Zvcm1pbmcgdGhlIGRhdGFzZXQsIHRoZSBkYXRhIHNlZW1zIHRvIGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24gbW9yZSBjbG9zZWx5LlRoaXMgaXMgYXBwYXJlbnQgaW4gdGhlIGhpc3RvZ3JhbXMgYXBwZWFyaW5nIG1vcmUgaW4gYSBiZWxsIHNoYXBlIGN1cnZlLicgfQoKIyBDb21iaW5lIG9sZCBhbmQgbmV3IGRhdGEgZm9yIGNvbXBhcmlzb24KZGZfY29tcGFyZSA8LSBkYXRhLmZyYW1lKAogIGJtaV9vcmlnaW5hbCA9IGRmX2ltcHV0ZWQkYm1pLAogIGJtaV90cmFuc2Zvcm1lZCA9IGRmX3RyYW5zJGJtaSwKICBibG9vZF9nbHVjb3NlX29yaWdpbmFsID0gZGZfaW1wdXRlZCRibG9vZF9nbHVjb3NlX2xldmVsLAogIGJsb29kX2dsdWNvc2VfdHJhbnNmb3JtZWQgPSBkZl90cmFucyRibG9vZF9nbHVjb3NlX2xldmVsCikKCiMgUmVzaGFwZSBkYXRhIGZvciBnZ3Bsb3QKZGZfbG9uZyA8LSBtZWx0KGRmX2NvbXBhcmUpCgojIFBsb3QgaGlzdG9ncmFtcwpnZ3Bsb3QoZGZfbG9uZywgYWVzKHggPSB2YWx1ZSwgZmlsbCA9IHZhcmlhYmxlKSkgKwogIGdlb21faGlzdG9ncmFtKGFscGhhID0gMC42LCBiaW5zID0gMzAsIHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogIGZhY2V0X3dyYXAofiB2YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkNvbXBhcmlzb24gb2YgT3JpZ2luYWwgdnMuIFRyYW5zZm9ybWVkIERhdGEiLCB4ID0gIlZhbHVlIiwgeSA9ICJDb3VudCIpCgoKYGBgCgoKCgojIEFuYWx5emluZyBEYXRhClRoZSBuZXh0IHN0ZXAgaXMgdG8gZmluZCB3aGljaCB2YXJpYWJsZXMgYXJlIHNpZ25pZmljYW50bHkgaW1wb3J0YW50IHdoZW4gdHJ5aW5nIHRvIHByZWRpY3QgZGlhYmV0ZXMuIEJ5IHVzaW5nIGZlYXR1cmUgc2VsZWN0aW9uLCB3ZSBhcmUgYWJsZSB0byBwcmVkaWN0IHBvc3NpYmxlIGJlc3QgZml0IG1vZGVscyBmb3Igb3VyIHZhcmlhYmxlLCBkaWFiZXRlcy4gRm9yIHRoaXMgZGF0YSwgd2Ugd2lsbCBmb2N1cyBvbiBsb2dpc3RpYyByZWdyZXNzaW9uLiBUaGUgdmFyaWFibGVzIG9mIGludGVyZXN0LCBkaWFiZXRlcywgaXMgYSBiaW5hcnkgdmFyaWFibGUgaW5kaWNhdGluZyBsaW5lYXIgcmVncmVzc2lvbiB3b3VsZCBub3QgbWFrZSBhbiBpZGVhbCBtb2RlbC4gCgoKCiMjIFJhbmRvbSBGb3Jlc3QKRmlyc3QsIHdlIHdpbGwgbG9vayBhdCB0aGUgYmVzdCBtb2RlbCBzZWxlY3RlZCBieSBmZWF0dXJlIHNlbGVjdGlvbiB0aHJvdWdoIHJhbmRvbSBmb3Jlc3Q6CmBgYHtyfQoKIyBQcmVwYXJlIHRoZSBkYXRhCmRmX3RyYW5zJGRpYWJldGVzIDwtIGFzLmZhY3RvcihkZl90cmFucyRkaWFiZXRlcykKCgojIFNldCB1cCBSRkUgY29udHJvbCB3aXRoIHJhbmRvbSBmb3Jlc3QKY29udHJvbCA8LSByZmVDb250cm9sKGZ1bmN0aW9ucyA9IHJmRnVuY3MsIG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwKQoKIyBBcHBseSBSRkUgdG8gaWRlbnRpZnkgdG9wIGZlYXR1cmVzCnJlc3VsdHMgPC0gcmZlKAogIHggPSBkZl90cmFuc1ssICFjb2xuYW1lcyhkZl90cmFucykgJWluJSAiZGlhYmV0ZXMiXSwKICB5ID0gZGZfdHJhbnMkZGlhYmV0ZXMsCiAgc2l6ZXMgPSBjKDE6OSksCiAgcmZlQ29udHJvbCA9IGNvbnRyb2wKKQoKIyBQcmludCB0aGUgc2VsZWN0ZWQgZmVhdHVyZXMKbW9kZWxzPC1kYXRhLmZyYW1lKHByZWRpY3RvcnMocmVzdWx0cykpCnBhbmRlcihtb2RlbHMsIGNhcHRpb249IlJhbmRvbSBGb3Jlc3QgU2VsZWN0ZWQgTW9kZWwiLHBvc2l0aW9uPSJjZW50ZXIiKQoKCmBgYAoKVGhlIHRhYmxlIHNob3dzIHRoZSBzZWxlY3RlZCB2YXJpYWJsZXMgcmFuZG9tIGZvcmVzdCBoYXMgc2VsZWN0ZWQgdG8gdXNlIGZvciBvdXIgbW9kZWwKCgojIyBTdGVwd2lzZSBMb2dpc3RpYyBSZWdyZXNzaW9uCk5leHQsIGxldCdzIGxvb2sgYW5kIHN0ZXB3aXNlIGxvZ2lzdGljIHJlZ3Jlc3Npb24KCmBgYHtyfQojU3RlcHdpc2UgTG9naXN0aWMgUmVncmVzc2lvbgojIEZpdCBhIGZ1bGwgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB3aXRoIGFsbCBwcmVkaWN0b3JzCmZ1bGxfbW9kZWwgPC0gZ2xtKGRpYWJldGVzIH4gLiwgZGF0YSA9IGRmX3RyYW5zLCBmYW1pbHkgPSBiaW5vbWlhbCkKCiMgUGVyZm9ybSBzdGVwd2lzZSBzZWxlY3Rpb24gKGRlZmF1bHQgaXMgYmFja3dhcmQgZWxpbWluYXRpb24pCnN0ZXBfbW9kZWwxIDwtIHN0ZXAoZnVsbF9tb2RlbCwgZGlyZWN0aW9uID0gImJvdGgiKQpwYW5kZXIoc3VtbWFyeShzdGVwX21vZGVsMSkpCgpgYGAKClRoZSBjb2VmZmljaWVudHMgc2hvd24gYWJvdmUgYXJlIHRoZSBvbmVzIHN0ZXB3aXNlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaGFzIGNob3NlbiBmb3IgdGhlIGZpbmFsIG1vZGVsLiBUaGV5IGFyZSBIYkExYyBsZXZlbCwgYmxvb2QgZ2x1Y29zZSBsZXZlbCwgYm1pLCBoeXBlcnRlbnNpb24sIGdlbmRlciwgYW5kIGFnZS4gCgpCb3RoIHNlbGVjdGlvbiB0eXBlcyBzZWxlY3RlZCB0aGUgc2FtZSBtb2RlbCEgSG93ZXZlciBJIHdpbGwgc3RpbGwgZ28gdGhyb3VnaCB0aGUgc3RlcHMgb2YgY3Jvc3MtdmFsaWRhdGlvbiBhcyB0aG91Z2ggSSB3YXMgY29tcGFyaW5nIHRoZSB0d28gbW9kZWxzLgoKIyBDcm9zcy1WYWxpZGF0aW9uCgpMZXQncyBleHBsb3JlIGNyb3NzLXZhbGlkYXRpb24gdG8gc2VlIHdoaWNoIG1vZGVsIGlzIGJlc3QgZml0LiBGb3IgbG9naXN0aWMgcmVncmVzc2lvbiwgaXQgaXMgbWVhbmluZ2Z1bCB0byBsb29rIGF0IGFjY3VyYWN5IGFuZCBrYXBwYS4gCmBgYHtyfQoKI2FkZCBjbGFzc2lmaWNhdGlvbgpkZl90cmFucyRkaWFiZXRlczwtIGZhY3RvcihpZmVsc2UoZGZfdHJhbnMkZGlhYmV0ZXM9PTEsICJZZXMiLCJObyIpKQoKdHJhaW5fY29udHJvbCA8LSB0cmFpbkNvbnRyb2woCiAgbWV0aG9kID0gImN2IiwgICAgICAgICAjIGNyb3NzLXZhbGlkYXRpb24KICBudW1iZXIgPSAxMCwgICAgICAgICAgICMgMTAtZm9sZAogIGNsYXNzUHJvYnMgPSBUUlVFICMgdXNlIGlmIHlvdSdyZSB0cmFja2luZyBBVUMsIFNlbnNpdGl2aXR5LCBldGMuCikKCiNydW4gQ1YgbW9kZWwKY3ZfbW9kZWwgPC0gdHJhaW4oCiAgZGlhYmV0ZXMgfiBoeXBlcnRlbnNpb24gKyBnZW5kZXIgK2FnZSArIEhiQTFjX2xldmVsICsgYmxvb2RfZ2x1Y29zZV9sZXZlbCArIGhlYXJ0X2Rpc2Vhc2UgKyBibWksIAogIGRhdGE9ZGZfdHJhbnMsIAogIG1ldGhvZCA9ICJnbG0iLCAKICBmYW1pbHkgPSAiYmlub21pYWwiLCAKICB0ckNvbnRyb2wgPSB0cmFpbl9jb250cm9sCiAgKQoKcGFuZGVyKHByaW50KGN2X21vZGVsKSkKCmBgYAoKQWNjdXJhY3kgc2hvd3MgdGhlIG92ZXJhbGwgY29ycmVjdG5lc3Mgb2YgdGhlIG1vZGVsIHByZWRpY3Rpb25zIGFuZCBrYXBwYSBtZWFzdXJlcyB0aGUgbGV2ZWxzIG9mIGFncmVlbWVudCBiZXR3ZWVuIHZhcmlhYmxlcy4gVmFsdWVzIGNsb3NlciB0byAxIHN1Z2dlc3QgaGlnaGVyIGFjY3VyYWN5IGFuZCBiZXR0ZXIgYWdyZWVtZW50LiBUaGlzIG1vZGVsIHN1Z2dlc3RzIGhpZ2ggYWNjdXJhY3kgYW5kIGhpZ2ggYWdyZWVtZW50IGJhc2VkIG9uIHRoZSB2YWx1ZXMuCgojIFJPQyBDdXJ2ZSBhbmQgQU9DIEN1cnZlCgojIyBDb25mdXNpb24gTWF0cmljZXMKCioqUk9DKiogaXMgYWxzbyBrbm93biBhcyBSZWNlaXZlciBPcGVyYXRpbmcgQ2hhcmFjdGVyaXN0aWMgQW5hbHlzaXMuIEl0IGlzIGEgdGVjaG5pcXVlIHVzaW5nIGdyYXBocyB0aGF0IGV2YWx1YXRlcyB0aGUgcGVyZm9ybWFuY2Ugb2YgYSBiaW5hcnkgbW9kZWwuIEJlZm9yZSBwbG90dGluZyB0aGUgUk9DIGN1cnZlLCBpdCBpcyBuZWNlc3NhcnkgdG8gY2FsY3VsYXRlIHRoZSB0cnVlIHBvc2l0aXZlIHJhdGUgKFRQUikgYW5kIGZhbHNlIHBvc2l0aXZlIHJhdGUgKEZQUikuIEJlbG93LCBhcmUgY29uZnVzaW9uIG1hdHJpY2VzIHRoYXQgd2VyZSB1c2VkIHRvIGNhbGN1bGF0ZSB0aG9zZSB2YWx1ZXMuCmBgYHtyfQoKI1JPQyBhbmQgQVVDCmRmX3RyYW5zJGRpYWJldGVzIDwtIGFzLmZhY3RvcihkZl90cmFucyRkaWFiZXRlcykKCiMgZml0IGEgbG9naXN0aWMKbW9kZWwubG9naXQgPC0gZ2xtKGRpYWJldGVzIH4gYWdlICsgZ2VuZGVyKyBibWkraHlwZXJ0ZW5zaW9uICsgaGVhcnRfZGlzZWFzZSArIGJsb29kX2dsdWNvc2VfbGV2ZWwrIEhiQTFjX2xldmVsICwgZmFtaWx5ID0gYmlub21pYWwsIGRhdGEgPSBkZl90cmFucykKIyBwcmVkaWN0IHByb2JhYmlsaXR5IG9mIFAoWSA9ICJZZXMiKQpwcm9iYWJpbGl0aWVzIDwtIHJvdW5kKGFzLnZlY3RvcihwcmVkaWN0KG1vZGVsLmxvZ2l0LCB0eXBlID0gInJlc3BvbnNlIikpLDMpCiMKdGhyZXNob2xkcyA8LSBjKDAuMCwgMC4yNSwgMC41LCAwLjc1LCAxLjApCgojIExvb3AgdGhyb3VnaCB0aHJlc2hvbGRzIGFuZCBjcmVhdGUgY29uZnVzaW9uIG1hdHJpY2VzCmZvciAodGhyZXNob2xkIGluIHRocmVzaG9sZHMpIHsKICBjYXQoIlxuQ29uZnVzaW9uIE1hdHJpeCBmb3IgVGhyZXNob2xkID0iLCB0aHJlc2hvbGQsICJcbiIpCiAgCiAgIyBDb252ZXJ0IHByb2JhYmlsaXRpZXMgdG8gcHJlZGljdGlvbnMKICAjIGFtOiAxID0gbWFudWFsIHRyYW5zbWlzc2lvbiwgMCA9IGF1dG9tYXRpYyB0cmFuc21pc3Npb24KICBwcmVkaWN0aW9ucyA8LSBpZmVsc2UocHJvYmFiaWxpdGllcyA+IHRocmVzaG9sZCwgIlllcyIsICJObyIpCiAgICBhbGxfbGV2ZWxzIDwtIHVuaW9uKGxldmVscyhmYWN0b3IoZGZfdHJhbnMkZGlhYmV0ZXMpKSwgbGV2ZWxzKGZhY3RvcihwcmVkaWN0aW9ucykpKQogICAgIyBHZW5lcmF0ZSBjb25mdXNpb24gbWF0cml4CiAgY20gPC0gY29uZnVzaW9uTWF0cml4KGZhY3RvcihwcmVkaWN0aW9ucywgbGV2ZWxzPWFsbF9sZXZlbHMpLCBmYWN0b3IoZGZfdHJhbnMkZGlhYmV0ZXMsbGV2ZWxzPWFsbF9sZXZlbHMpLCBwb3NpdGl2ZSA9ICJZZXMiKQogIHByaW50KGNtJHRhYmxlKQp9CgpgYGAKCgoKIyMgUk9DIEN1cnZlCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwnVGhlIHBsb3Qgc2hvd3MgdGhlIHBhdGggb2YgdGhlIFJPQyBjdXJ2ZS4nfQoKI2NyZWF0ZSBST0MgY3VydmUKClRQUiA9IGMoMSw5MTUwMC8oOTE1MDArMCksIDkxMzU2Lyg5MTM1NisxNDQpLCA5MDYzMi8oOTA2MzIrODY4KSwgODgxNjAvKDg4MTYwKzMzNDApLCAwLyg5MTUwMCswKSkKRlBSID0gYygxLDM1Mi8oMzUyKzgxNDgpLCA0MjgyLyg0MjgyKzQyMTgpLCAzMTkzLyg1MzA3KzMxOTMpLCAyMTc4LygyMTc4KzYzMjIpLCAwLyg4NTAwKzApKQpwbG90KEZQUiwgVFBSLCB0eXBlID0gImIiLCBtYWluID0gIkFuIElsbHVzdHJhdGl2ZSBST0MgQ3VydmUiLCBjb2wgPSJibHVlIiwKICAgICB4bGFiPSIxIC0gU3BlY2lmaXR5IChGUFIpIiwgeWxhYiA9ICJTZW5zaXRpdml0eSAoVFBSKSIpCiMgYWRkIGEgb2ZmLWRpYWdvbmFsIHJlcHJlc2VudGluZyByYW5kb20gZ3Vlc3MgYWxnb3JpdGhtIGluIGJpbmFyeSBwcmVkaWN0aW9uCmFibGluZSgwLDEsIGx0eSA9IDIsIGNvbCA9ICJyZWQiKQojIGxlZ2VuZApsZWdlbmQoImJvdHRvbXJpZ2h0IiwgYygiTG9naXN0aWMgTW9kZWwiLCAiUmFuZG9tIEd1ZXNzIiksCiAgICAgICBjb2w9YygiYmx1ZSIsICJyZWQiKSwgbHR5ID0gMToyLCBidHk9Im4iLCBjZXggPSAwLjkpCmBgYAoKCgoKIyMgQVVDIChBcmVhIHVuZGVyIHRoZSBDdXJ2ZSkKCioqQVVDKiogcXVhbnRpZmllcyB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIFJPQyBjdXJ2ZSBpbnRvIGEgc2luZ2xlIHZhbHVlIHRoYXQgcmFuZ2VzIGZyb20gMCB0byAxLiBUaGUgcGxvdCBiZWxvdyB1c2VzIHRoZSBSaWVtYW5uIFN1bSBhcHByb3hpbWF0aW9uIHRvIGVzdGltYXRlIHRoZSBhcmVhIHVuZGVyIHRoZSBjdXJ2ZS4KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCdUaGUgcGxvdCBlc3RpbWF0ZXMgdGhlIGFyZWEgb2YgdGhlIFJPQyBDdXJ2ZS4gVGhlIHJlZ2lvbiBpcyBkaXZpZGVkIGludG8gc3VicmVnaW9ucywgQSxCLCBhbmQgQy4gVGhlc2UgdmFsdWVzIGFyZSB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgYXJlYSB1bmRlciB0aGUgY3VydmUuJyB9CiNBVUMKVFBSID0gcm91bmQoYygxLDkxNTAwLyg5MTUwMCswKSwgOTEzNTYvKDkxMzU2KzE0NCksIDkwNjMyLyg5MDYzMis4NjgpLCA4ODE2MC8oODgxNjArMzM0MCksIDAvKDkxNTAwKzApKSwzKQpGUFIgPSByb3VuZChjKDEsMzUyLygzNTIrODE0OCksIDQyODIvKDQyODIrNDIxOCksIDMxOTMvKDUzMDcrMzE5MyksIDIxNzgvKDIxNzgrNjMyMiksIDAvKDg1MDArMCkpLDMpClRQUjAgPSBUUFJbNzoxXQpGUFIwID0gRlBSWzc6MV0KI3Bsb3QoRlBSMCwgVFBSMCwgdHlwZSA9ICJiIikKZGF0U2VuU3BlID0gZGF0YS5mcmFtZShUUFIwLCBGUFIwKQpnZ1JPQyA9IGdncGxvdChkYXRhID0gZGF0U2VuU3BlLCBhZXMoeCA9IEZQUjAsIHk9VFBSMCkpICsKICAgICAgICBnZW9tX2xpbmUoY29sID0gInN0ZWVsYmx1ZSIpICsKICAgICAgICBnZW9tX3BvaW50KGNvbCA9ICJyZWQiKSArCiAgICAgICAgZ2VvbV9zZWdtZW50KHggPSBGUFIwLCB5ID0gMCwgeGVuZCA9IEZQUjAsIHllbmQgPSBUUFIwLCBjb2xvciA9IDQpICsKICAgICAgICBnZW9tX3NlZ21lbnQoeCA9IDAsIHkgPSAwLCB4ZW5kID0gRlBSMFs3XSwgeWVuZCA9IDAsIGNvbG9yID0gNikgKwogICAgICAgIGdndGl0bGUoIkFwcHJveGltYXRpbmcgdGhlIEFVQyBvZiBMb2dpc3RpYyBNb2RlbCIpICsKICAgICAgICB4bGFiKCIxLXNwZWNpZmljaXR5IChGUFIpIikgKyAKICAgICAgICB5bGFiKCJTZW5zaXRpdml0eSAoVFBSKSIpICsKICAgICAgICBhbm5vdGF0ZSgidGV4dCIsIHggPSAwLjAyNSwgeSA9IDAuMTI1LCBsYWJlbD0gIkEiKSArIAogICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDAuMTA1LCB5ID0gMC41LCBsYWJlbCA9ICJCIikgKwogICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDAuNjA1LCB5ID0gMC41LCBsYWJlbCA9ICJDIikgKwogICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44LCAwLjIpLAogICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAuMTUsIDAuMTUsIDAuNzUsIDAuMTUpLCAiaW5jaGVzIiksCiAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAyLCBjb2xvdXIgPSAibmF2eSIsIGxpbmV0eXBlPTEpKQojIHBhcnRpdGlvbiB0aGUgcmVnaW9uIHVuZGVyIHRoZSBST0MgaW50byB0cmFwZXpvaWRzCmdncGxvdGx5KGdnUk9DKQpgYGAKCiMjIEFVQyBWYWx1ZQoKVGhlIGFyZSB1bmRlciB0aGUgY3VydmUgaXMgZXF1YWwgdG8gMC45Nzk1IHdoaWNoIGlzIGNsb3NlIHRvIDEsIHRodXMgaW5kaWNhdGluZyBhbiBpZGVhbCBtb2RlbC4KYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCdUaGUgYXJlYSB1bmRlciB0aGUgY3VydmUgaXMgMC45Nzk1IHdoaWNoIGlzIGNsb3NlIHRvIDEsIHRoaXMgaW5kaWNhdGVzIGFuIGlkZWFsIG1vZGVsLid9CkE8LSgwLjA0MSoxKS8yCkI8LSAoKDAuNTA0LTAuMDQxKSoxKQpDPC0gKCgxLTAuNTA0KSoxKQoKQVVDPC0gQStCK0MKcGFuZGVyKEFVQywgY2FwdGlvbj0gIkFyZWEgdW5kZXIgdGhlIEN1cnZlIiwgcG9zaXRpb249IkNlbnRlciIpCgpgYGAKCiMgQ29uY2x1c2lvbiBmb3IgTW9kZWwgRml0Ck91ciBiZXN0IGZpdCBtb2RlbCBpcyA6CiQkClx0ZXh0eyBEaWFiZXRlc30gPSA5Ljk5IC0gMC4yN1x0aW1lcyBcdGV4dHtnZW5kZXJ9IC0gMS4wM1x0aW1lcyBcdGV4dHthZ2V9ICAtMC44XHRpbWVzIFx0ZXh0e2h5cGVydGVuc2lvbn0gLSAwLjc2XHRpbWVzIFx0ZXh0e2hlYXJ0IGRpc2Vhc2V9IC0xMC4yNFx0aW1lcyBcdGV4dHtibWl9IC0gMi40OVx0aW1lcyBcdGV4dHtIYkExYyBsZXZlbH0gLTEwLjNcdGltZXMgXHRleHR7Ymxvb2QgZ2x1Y29zZSBsZXZlbH0KJCQKCgpUaGUgYmVzdCBmaXQgbW9kZWwgd2FzIHNlbGVjdGVkIGJhc2VkIG9uIGEgdmFyaWV0eSBvZiBkaWZmZXJlbnQgZmVhdHVyZXMuIEJvdGggc3RlcHdpc2Ugc2VsZWN0aW9uIGFuZCByYW5kb20gZm9yZXN0IHNlbGVjdGVkIHRoZSBtb2RlbCBhcyBiZXN0IGZpdC4gQWZ0ZXIgcnVubmluZyBwZXJmb3JtYW5jZSBhbmFseXNlcyBvbiB0aGUgbW9kZWwsIHRoZSBtb2RlbCB3YXMgc2hvd24gdG8gYmUgb2YgaGlnaCBwZXJmb3JtYW5jZS4gVGhpcyBtZWFucyB0aGF0IHRoZSB2YXJpYWJsZXMgY2hvc2VuIGZvciB0aGUgZmluYWwgbW9kZWwgYXJlIHNpZ25pZmljYW50IGZvciBwcmVkaWN0aW5nIGRpYWJldGVzLiBUaGUgbW9kZWwgY2hvc2Ugbm90IHRvIHNlbGVjdCBzbW9raW5nIGhpc3RvcnkgYXMgc2lnbmlmaWNhbnQgcHJlZGljdG9yIGZvciB0aGUgcmVzcG9uc2UgdmFyaWFibGUuIEEgcG9zc2libGUgc3VnZ2VzdGlvbiBmb3IgdGhpcyB3b3VsZCBiZSB0byByZWR1Y2UgdGhlIG51bWJlciBvZiByZXNwb25zZSB2YWx1ZXMgdG8gYSBiaW5hcnkgcmVzcG9uc2UuIFN1Y2ggYXMsICJIYXZlIHlvdSBldmVyIHNtb2tlZD8iIGFuZCBoYXZlIHRoZSByZXNwb25zZSBiZSAiWWVzIiBvciAiTm8iLiBUaGlzIGNvdWxkIGhlbHAgaW4gcHJlZGljdGluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gc21va2luZyBhbmQgZGlhYmV0ZXMuIAo=